WPF: важна ли привязка данных для модальных диалогов? - PullRequest
5 голосов
/ 10 августа 2009

(Я довольно новичок в WPF, поэтому этот вопрос может показаться очевидным или непоследовательным.)

Требуется отредактировать некоторую часть лежащих в основе бизнес-данных приложения из дочернего модального окна и обновлять данные, только если пользователь нажимает кнопку ОК в этом окне. Давайте назовем это окно SettingsDialog.

В этом случае все же целесообразно использовать привязку данных WPF для привязки элементов управления SettingsDialog к бизнес-данным? (И если да, то как обновлять бизнес-данные только тогда, когда пользователь нажимает кнопку ОК в SettingsDialog?)

Или лучше вручную назначать значения элементов управления SettingsDialog из бизнес-данных во время отображения SettingsDialog, а затем назначать их обратно только в том случае, если пользователь нажимает кнопку OK?

Каковы аргументы правильного выбора (меньший или более четкий код, производительность, расширяемость)?

Существует ли какой-нибудь признанный шаблон проектирования для подобных случаев?

РЕДАКТИРОВАТЬ: Я отметил ответ Bubblewrap как принятый, потому что он больше всего подходит для моего конкретного случая. Хотя ответы Гвардии и Джона также кажутся приемлемыми.

Подводя итог: использование привязки данных имеет ряд преимуществ. Это позволяет SettingsDialog ничего не знать о внутренних подключениях и зависимостях бизнес-объекта (если они есть), позволяет легко переключаться позднее из модального в немодальный режим, уменьшает зависимости между графическим интерфейсом и бизнес-данными.

Для реализации изменения объекта при нажатии кнопки ОК может использоваться клонирование / назначение объекта или объект может реализовывать интерфейс IEditableObject.

В некоторых тривиальных случаях использование привязки данных может привести к ненужным накладным расходам.

Ответы [ 5 ]

4 голосов
/ 10 августа 2009

Я уже сталкивался с аналогичными требованиями и предпочитаю два варианта, оба с использованием привязки данных.

В первом варианте мы клонируем объект и связываемся с клоном. Когда пользователь нажимает ОК, клонированный объект заменяется реальным объектом. Это в основном полезно при редактировании одного объекта за раз, и на объект не ссылаются напрямую другие объекты. Если на него есть ссылка, то вместо этого вы можете скопировать значения из вашего клона в оригинал, чтобы ссылки оставались нетронутыми. Это экономит работу, поскольку в редакторах не требуется никакой дополнительной работы, самое большее, вы должны определить 2 метода для вашего объекта, клон и, возможно, метод Apply для копирования значений из клона.

Второй вариант мы привязываем к исходному объекту, но сохраняем исходные значения в нашем диалоге редактирования, либо в локальных полях, либо во временном объекте данных. Когда пользователь нажимает кнопку ОК, ничего особенного не должно произойти, но когда пользователь нажимает кнопку отмены, мы возвращаем значения. Это в основном полезно, когда вы редактируете только несколько простых свойств в диалоговом окне.

Я предпочитаю решения для привязки данных, потому что оно не загрязняет диалоги редактирования логикой применения / отмены, которая, если она реализована в редакторах, очень зависит от вашего XAML: элементы управления могут быть переименованы, поле со списком может быть заменено текстовым полем и т. Д., Все что повлияет на код, который вручную получает данные от элементов управления.

Методы Clone / Apply должны быть только для ваших бизнес-объектов, которые в теории более стабильны, чем ваши редакторы пользовательского интерфейса. Даже если XAML изменится, в большинстве случаев ваши привязки могут остаться прежними. Например, изменение из поля со списком в текстовое поле означает только то, что вы привязываетесь к тексту, а не к SelectedValue, но фактическая привязка такая же.

4 голосов
/ 10 августа 2009

Один из вариантов - заставить ваш бизнес-объект реализовать IEditableObject .

  • Перед отображением окна, вызовите BeginEdit на вашем объекте
  • Если пользователь нажимает кнопку ОК, позвоните EndEdit
  • Если пользователь нажимает кнопку Отмена, звоните Отмена Редактировать

IEditableObject обычно используется в сценариях сетки данных, но он хорошо работает и для описанного вами случая. Кроме того, если ваш пользовательский интерфейс когда-либо изменится, чтобы разрешить встроенное редактирование в DataGrid, вам не придется менять бизнес-объект.

1 голос
/ 10 августа 2009

Вы можете использовать привязку данных для одностороннего обновления GUI, но если вы хотите отложить обновление бизнес-модели только после нажатия OK, лучше сделать это в коде. Связывание данных вообще в этом случае может быть ненужным.

Взять, к примеру, FolderBrowserDialog. Вы можете установить начальное значение на SelectedPath, прежде чем вызывать ShowDialog(), но дождитесь возвращения диалогового окна с помощью DialogResult.OK, прежде чем обрабатывать данные. Подобный подход должен работать для вашей ситуации.

0 голосов
/ 22 ноября 2013

Недавно я столкнулся с той же проблемой - у меня есть всплывающие диалоговые формы для редактирования свойств объекта. После некоторой настройки я получил приведенный ниже код, который, кажется, работает хорошо. Надеюсь, это кому-нибудь поможет.

Я использую это, чтобы показать всплывающую форму

    public static bool EditTask(MyTask task)
    {
        //make a backup object in case user clicks Cancel
        MyTask backupTask = new MyTask();
        CloneObject(task, backupTask);

        //dialog form uses data binding to the backupTask object
        MyTaskWindow f = new MyTaskWindow(backupTask);

        f.ShowDialog();
        if (f.DialogResult.HasValue && f.DialogResult.Value)
        {
            //user clicked "Ok" - clone everything back
            CloneObject(backupTask, task);
            return true;
        }
        else
        {                
            return false;
        }
    }

    //Reflection is used to clone object
    //copied from http://www.c-sharpcorner.com/UploadFile/ff2f08/deep-copy-of-object-in-C-Sharp/
    private static void CloneObject(object objSource, object objTarget)
    {
        //step : 1 Get the type of source object and create a new instance of that type
        Type typeSource = objSource.GetType();
        //object objTarget = Activator.CreateInstance(typeSource);

        //Step2 : Get all the properties of source object type
        PropertyInfo[] propertyInfo = typeSource.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

        //Step : 3 Assign all source property to taget object 's properties
        foreach (PropertyInfo property in propertyInfo)
        {
            //Check whether property can be written to
            if (property.CanWrite)
            {
                //Step : 4 check whether property type is value type, enum or string type
                if (property.PropertyType.IsValueType || property.PropertyType.IsEnum || property.PropertyType.Equals(typeof(System.String)))
                {
                    property.SetValue(objTarget, property.GetValue(objSource, null), null);
                }
                //else property type is object/complex types, so need to recursively call this method until the end of the tree is reached
                else
                {
                    object objPropertyValue = property.GetValue(objSource, null);
                    if (objPropertyValue == null)
                    {
                        property.SetValue(objTarget, null, null);
                    }
                    else
                    {
                        Type newTypeSource = objPropertyValue.GetType();
                        object newObjTarget = Activator.CreateInstance(newTypeSource);
                        CloneObject(objPropertyValue, newObjTarget);
                        property.SetValue(objTarget, newObjTarget, null);
                    }
                }
            }
        }            
    }
0 голосов
/ 18 ноября 2009

В обработчике загрузки формы Перейдите в коллекцию Bindings и установите для каждого DataSourceUpdateMode значение Never. На обработчике ОК установлено противоположное (DataSourceUpdateMode.OnValidation) и вызов формы ValidateChildren

если привязка осуществляется через GUI, новый член формы класса BindingSource Это немного упрощает привязки, доступные посредством CurrencyManager.Bindings, и вместо ValidateChildren можно использовать BindingSource.EndEdit.

...