In WPF data binding scenarios, the binding source is usually updated implicitly – if you, for example, edit the text of a bound TextBox
control, the underlying binding source is updated a soon as the control loses focus.
This is something you might want to prevent sometimes – a common scenario is a model dialog that provides a Cancel button to abort changes. The basic idea is that the underlying data remains unchanged until you commit all your changes at once if the dialog’s OK button is clicked.
The solution to prevent automatic updates of the binding source is to set the UpdateSourceTrigger property
to Explicit
, which prevents automatic updates of the underlying data item:
<TextBox Text="{Binding Path=Name, UpdateSourceTrigger=Explicit}" />
However, this feature comes with a catch: You’ll have to trigger updates on all your controls manually. Beatriz Costa posted a generic solution, but I found it a bit tedious to explicitly update every single control on my dialog. As a result, I came up with a solution that recursively processes a visual tree from a given starting point and updates all controls that provide one or several bindings of your choice:
/// <summary>
/// Recursively processes a given dependency object and all its
/// children, and updates sources of all objects that use a
/// binding expression on a given property.
/// </summary>
/// <param name="obj">The dependency object that marks a starting
/// point. This could be a dialog window or a panel control that
/// hosts bound controls.</param>
/// <param name="properties">The properties to be updated if
/// <paramref name="obj"/> or one of its childs provide it along
/// with a binding expression.</param>
public static void UpdateBindingSources(DependencyObject obj,
params DependencyProperty[] properties)
{
foreach (DependencyProperty depProperty in properties)
{
//check whether the submitted object provides a bound property
//that matches the property parameters
BindingExpression be =
BindingOperations.GetBindingExpression(obj, depProperty);
if (be != null) be.UpdateSource();
}
int count = VisualTreeHelper.GetChildrenCount(obj);
for(int i=0; i<count; i++)
{
//process child items recursively
DependencyObject childObject = VisualTreeHelper.GetChild(obj, i);
UpdateBindingSources(childObject, properties);
}
}
Using the above method is quite simple: Just set a starting point (window, grid, whatever) along with an arbitrary number of dependency properties you’d like to have processed. As an example: The snipped below commits all bound Text
properties of a dialog’s TextBox
controls as well bound items of XamComboEditor
dropdown controls:
//update TextBox and ComboBox controls of the dialog
DependencyProperty dpText = TextBox.TextProperty;
DependencyProperty dpSelectedItem = XamComboEditor.SelectedItemProperty;
UpdateBindingSources(this, dpText, dpSelectedItem);