2009-08-10 2 views
4

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

Требуется отредактировать некоторые бизнес-данные некоторых частей приложения из дочернего модального окна и обновить только данные если пользователь нажмет кнопку OK в этом окне. Назовем это окно SettingsDialog.

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

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

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

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

EDIT: Я отметил ответ Bubblewrap как принятый, потому что он подходит для моего конкретного конкретного случая больше всего. Хотя ответы Гвардии и Джона также кажутся приемлемыми.

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

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

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

ответ

4

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

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

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

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

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

1

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

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

4

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

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

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

+0

спасибо! Я взял маршрут IEditableObject, и я не жалею об этом. –

0

On Form Load handler Перейдите к сборкам Bindings и установите каждый DataSourceUpdateMode в Never. На OK обработчика установлен на противоположный (DataSourceUpdateMode.OnValidation) и называют образование ValidateChildren

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

0

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

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

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); 
        } 
       } 
      } 
     }    
    } 
Смежные вопросы