Home > WPF > Explicitly update binding sources

Explicitly update binding sources

January 16th, 2008

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);

Author: Categories: WPF Tags: , ,
  1. June 28th, 2008 at 08:14 | #1

    I’ve updated your code so you don’t need to pass DependencyProperty[] properties.

    public static class DialogHelper
        {
            /// 
            /// 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.
            /// 
            /// The dependency object that marks a starting
            /// point. This could be a dialog window or a panel control that
            /// hosts bound controls.
            /// The properties to be updated if
            ///  or one of its childs provide it along
            /// with a binding expression.
            public static void UpdateBindingSources( DependencyObject obj)
            {
                IEnumerable props = obj.EnumerateDependencyProperties();
                foreach (DependencyProperty p in props)
                {
                    Binding b = BindingOperations.GetBinding(obj, p);
                    if (b.UpdateSourceTrigger == UpdateSourceTrigger.Explicit)
                    {
                        //check whether the submitted object provides a bound property
                        //that matches the property parameters
                        BindingExpression be =
                          BindingOperations.GetBindingExpression(obj, p);
                        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);
                }
            }
    
            public static void UpdateAllSources(this Control w)
            {
                UpdateBindingSources(w);
            }
    }
    
    public static class DependencyObjectExtensions
        {
           public static IEnumerable EnumerateDependencyProperties(this DependencyObject element)
            {
                LocalValueEnumerator lve = element.GetLocalValueEnumerator();
    
                while (lve.MoveNext())
                {
                    LocalValueEntry entry = lve.Current;
                     if (BindingOperations.IsDataBound(element, entry.Property))
                    {
                        yield return entry.Property;
                    }
                }
            }
    
        }
  2. September 12th, 2008 at 00:41 | #2

    Good post! I was having this exact issue and your solution seems to work just fine for me.

  3. Sam
    September 30th, 2009 at 14:19 | #3

    Awesome Job!! I used your code to do a general refresh of bindings at program startup – in order to display the results of validation w/o requiring the user to ‘invalidate’ each entry (and w/o requiring me to list out each control and do a Binding UpdateSource()… thanks again.

  4. Andrei
    January 23rd, 2012 at 00:32 | #4

    Hi. I tried using the solution and though it does work on controls like TextBox and such , it is not updating the bindings that i have on a ListView items.

  5. Yemi
    April 20th, 2013 at 14:19 | #5

    Splendid! thanks Stefan also!

  6. Novie
    November 29th, 2014 at 18:54 | #6

    Thank you very much for this post, and also to Stefan Olson. Such a “bulk” functionality saves me of much tedious work. It makes an excellent bridge for getting into WPF – keeping me from the “F” (Framework overhead) in it, so I may still use the oldschool imperative “Fetch input / Show output” approach.
    For this, I found it convenient to also have the values transport work the opposite direction.

    public static class DependencyObjectExtension
    {
    ///
    /// Gets Values from View and stores them in the POCO data object
    ///
    ///
    public static void UpdateSource(this DependencyObject obj)
    {
    obj.UpdateBinding(true);
    }

    ///
    /// Gets Values from the POCO object and shows them in the View’s controls
    ///
    ///
    public static void UpdateTarget(this DependencyObject obj)
    {
    obj.UpdateBinding(false);
    }

    public static void UpdateBinding(this DependencyObject obj, bool toSource=true)
    {
    IEnumerable properties =obj.EnumerateDependencyProperties();
    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)
    if (toSource)
    be.UpdateSource();
    else
    be.UpdateTarget();

    }

    int count = VisualTreeHelper.GetChildrenCount(obj);
    for (int i = 0; i < count; i++)
    {
    //process child items recursively
    DependencyObject childObject = VisualTreeHelper.GetChild(obj, i);
    UpdateBinding(childObject,toSource);
    }
    }

    public static IEnumerable EnumerateDependencyProperties(this DependencyObject element)
    {
    LocalValueEnumerator lve = element.GetLocalValueEnumerator();

    while (lve.MoveNext())
    {
    LocalValueEntry entry = lve.Current;
    if (BindingOperations.IsDataBound(element, entry.Property))
    {
    yield return entry.Property;
    }
    }
    }
    }

  1. No trackbacks yet.