views:

291

answers:

4

(I'm pretty new to WPF, so this question may seem obvious or inconsistent.)

There is a requirement to edit some piece of application's underlying business data from a child modal window, and to update the data only if the user presses OK button in this window. Let's call this window SettingsDialog.

In this case, is it still reasonable to use WPF data binding to bind SettingsDialog's controls to business data? (And if so, how to update business data only when the user presses SettingsDialog's OK button?)

Or is it better to manually assign SettingsDialog's controls' values from business data while SettingsDialog is showing, and then assign them back only if user presses OK button?

What are arguments of correct choice (smaller or clearer code, performance, extensibility)?

Is there some acknowledged design pattern for similar cases?

EDIT: I marked Bubblewrap's answer as accepted, because it fits my own concrete case the most. Though, Guard's and John's answers also seem acceptable.

To summarize: using data binding has some advantages. It allows SettingsDialog to know nothing about business object internal connections and dependencies (if there are any), allows to switch later from modal to non-modal mode easily, reduces dependencies between GUI and business data.

To implement changing of object upon OK button click, object cloning/assigning may be used, or object may implement IEditableObject interface.

In some trivial cases, though, using data binding may have some unnecessary overhead.

+1  A: 

You can use data-binding for one-way updating to the GUI, but if you want to postpone updating the business model only after OK is pressed, it's better to do this in code. Data-binding at all in this case may be unnecessary.

Take, for example, FolderBrowserDialog. You can set an initial value to SelectedPath before you call ShowDialog(), but you wait for the dialog to return with DialogResult.OK before you process the data. A similar approach should work for your situation.

Will Eddins
+3  A: 

I have encountered similar requirements before, and prefer two variants, both using databinding.

In the first variant we clone the object and bind to the clone. When the user presses OK, the cloned object replaces to real object. This is mostly useful when editing one object at a time, and the object is not referenced directly by other objects. If it is referenced, then instead you could copy the values from your clone to your original, so that references remain intact. This saves work because no extra work is required in the editors, at most you must define 2 methods on your object, a Clone and possible an Apply method to copy the values from the clone.

The second variant we bind to the original object, but we store the original values in our editing dialog, either in local fields or in a temporary data-object. When the user presses OK, nothing special has to happen, but when the user presses cancel we revert the values. This is mostly useful when you edit only a few simple properties in the dialog.

I prefer databinding solutions because it doesnt pollute the editing dialogs with apply/cancel logic, which if implemented in the editors is very dependent on your XAML: controls can be renamed, a combobox can be replaced by a textbox etc, all of which would affect code which manually assings data from controls.

The Clone/Apply methods only need to be on your business objects, which in theory are more stable than your UI editors. Even if the XAML changes, in most cases your bindings can remain the same. For example a change from combobox to textbox only means you bind to Text instead of SelectedValue, but the actual binding is the same.

Bubblewrap
+3  A: 

One option is to have your business object implement IEditableObject.

  • Before showing the window, call BeginEdit on your object
  • If the user clicks OK, call EndEdit
  • If the user clicks Cancel, call CancelEdit

IEditableObject is typically used in data grid scenarios, but it works well for the case you described too. Plus, if your UI ever changes to allow inline editing in a DataGrid, you won't have to change your business object.

John Myczek
Thank you!I've taken the IEditableObject route and I don't regret it.
Andrei Rinea
A: 

On Form Load handler Go over Bindings collection and set each DataSourceUpdateMode to Never. On OK handler set to opposite (DataSourceUpdateMode.OnValidation) and call form ValidateChildren

if binding done through GUI there would be new form member of class BindingSource It simplifies a bit - bindings acessible by CurrencyManager.Bindings, and BindingSource.EndEdit can be used instead of ValidateChildren.

vlad