Here it is: The UpdateSourceTrigger for PropertyChanged in Silverlight

Today I’ll show you how to implement a PropertyChanged-UpdateSourceTrigger for Silverlight. In Silverlight a Data Binding can have different UpdateSourceTriggers. An UpdateSourceTrigger specifies, when a TwoWay-DataBinding will update its source with the value of the Target-Property.

In most cases you have a TwoWay-DataBinding on TextBoxes. When the user types something into a TextBox, it should be written back to the underlying Data-Object. The other way, when the underlying Data-Object changes, the TextBox should show the actual value of the bound property.

In this post I’ll focus on the moment of writing the data back to the underlying object. In other words, when the data is updated with the text the user has typed in.

In Silverlight the underlying object is updated after the TextBox has lost its focus. In WPF, the UpdateSourceTrigger-Enum has a Member PropertyChanged. If you set the UpdateSourceTrigger-Property of the Data Binding to that value, the underlying object will be updated everytime the user changes the text. Unfortunately Silverlight doesn’t contain the PropertyChanged-Value in its UpdateSourceTrigger-Enum. It only contains a Default- and a LostFocus-Member. As the name implies, LostFocus will update the source when the TextBox loses its focus. But an Attached Property would do the trick.

When I tried to solve this problem I came across a post of Michael Sync, who showed up a solution with an attached-Property that works by stealing the focus everytime the Text of a TextBox changes, and immediately set it back to the TextBox again. Find his post under http://michaelsync.net/2009/06/10/silverlight-attached-properties-bindingupdatesourcetriggerpropertychanged

As I got deep knowledge about WPFs Binding-Engine, I could produce a solution for Silverlight, and I think I got a similar solution to Michael’s, but my solution is built closer on the binding-engine and doesn’t need a focus-trick. So, some details: Behind each Binding, a BindingExpression does the real work. All you have to do when the Text of the TextBox changes is to get the BindingExpression of the Data Binding and to call its UpdateSource-Method. So my Attached-Property-Class looks like the one below (Feel free to use the source in your projects, but please keep the reference to www.thomasclaudiushuber.com). As it is, it just works for the Text-Property of TextBoxes.

/// <summary>
/// Supports a PropertyChanged-Trigger for DataBindings 
/// in Silverlight. Works just for TextBoxes
/// (C) Thomas Claudius Huber 2009
/// http://www.thomasclaudiushuber.com
/// </summary>
public class BindingHelper
{
  public static bool GetUpdateSourceOnChange
    (DependencyObject obj)
  {
    return (bool)obj.GetValue(UpdateSourceOnChangeProperty);
  }

  public static void SetUpdateSourceOnChange
    (DependencyObject obj, bool value)
  {
    obj.SetValue(UpdateSourceOnChangeProperty, value);
  }

  // Using a DependencyProperty as the backing store for ...
  public static readonly DependencyProperty 
    UpdateSourceOnChangeProperty =
      DependencyProperty.RegisterAttached(
      "UpdateSourceOnChange",
      typeof(bool),
      typeof(BindingHelper),
      new PropertyMetadata(false, OnPropertyChanged));

  private static void OnPropertyChanged
    (DependencyObject obj,
    DependencyPropertyChangedEventArgs e)
  {
    var txt = obj as TextBox;
    if (txt == null)
      return;
    if((bool)e.NewValue)
    {
      txt.TextChanged += OnTextChanged;
    }
    else
    {
      txt.TextChanged -= OnTextChanged;
    }
  }
  static void OnTextChanged(object sender,
    TextChangedEventArgs e)
  {
    var txt = sender as TextBox; 
    if(txt==null)
      return;
    var be = txt.GetBindingExpression(TextBox.TextProperty);
    if (be != null)
    {
      be.UpdateSource();
    }
  }
}

The usage of the BindingHelper-class is very simple. Just add it to your project, insert a matching xmlns to your XAML file that contains the CLR-Namespace the BindingHelper-class is in. When that is done, you can simply set the UpdateSourceOnChange-Property on a TextBox to true, and if the Text-Property is databound, you’ll have a Data Binding that will update its source on every PropertyChange. Like in WPF. :-)

<UserControl ...
    xmlns:local="clr-namespace:BindingHelperExample">
  <Grid x:Name="LayoutRoot">
      ...
    <TextBox Text="{Binding FirstName, Mode=TwoWay}" 
    local:BindingHelper.UpdateSourceOnChange="True" />
      ...
    </Grid>
</UserControl>

If this post helped you, please kick it. :-)

kick it on DotNetKicks.com

Share this post

Comments (14)

  • Jean-Marie Pirelli Reply

    Thanks for sharing !

    March 31, 2010 at 10:36 am
  • John Reply

    Very Cool Thanks !!

    June 8, 2010 at 8:27 am
  • JohnStarr Reply

    Any chance of a VB.NET version?
    Tried converting, but Iam stuck on:

    txt.TextChanged += OnTextChanged;

    This is not allowed in VB.NET

    July 21, 2010 at 2:59 pm
  • Simon Reply

    Thanks a lot, you saved my day!

    February 2, 2011 at 10:32 am
  • Florian B. Reply

    txt.TextChanged += OnTextChanged;
    VB
    addhandler txt.TextChanged,addressof OnTextChanged
    -=
    removehandler txt.TextChanged,addressof OnTextChanged

    September 18, 2012 at 1:26 pm
  • Florian B. Reply

    For help in VB :
    Public Class BindingHelper
    Public Shared Function GetUpdateSourceOnChange(obj As DependencyObject) As Boolean
    Return obj.GetValue(UpdateSourceOnChangeProperty)
    End Function
    Public Shared Sub SetUpdateSourceOnChange(obj As DependencyObject, value As Boolean)
    obj.SetValue(UpdateSourceOnChangeProperty, value)
    End Sub
    Public Shared ReadOnly UpdateSourceOnChangeProperty As DependencyProperty =
    DependencyProperty.RegisterAttached(“UpdateSourceOnChange”, GetType(Boolean), GetType(BindingHelper), New PropertyMetadata(False, AddressOf OnPropertyChanged))

    Private Shared Sub OnPropertyChanged(obj As DependencyObject, e As DependencyPropertyChangedEventArgs)
    Dim TxtBox As TextBox = obj
    If TxtBox IsNot Nothing Then
    If e.NewValue Then
    AddHandler TxtBox.TextChanged, AddressOf OnTextChanged
    Else
    RemoveHandler TxtBox.TextChanged, AddressOf OnTextChanged
    End If
    End If
    End Sub
    Private Shared Sub OnTextChanged(sender As Object, e As TextChangedEventArgs)
    Dim TxtBox As TextBox = sender
    If TxtBox IsNot Nothing Then
    Dim be = TxtBox.GetBindingExpression(TextBox.TextProperty)
    If be IsNot Nothing Then
    be.UpdateSource()
    End If
    End If
    End Sub
    End Class

    September 18, 2012 at 1:30 pm
  • Pham Phuong Nguyen » Tổng quan về Code4Fun Toolkit cho Windows Phone Reply

    […] Code4Fun là bộ toolkit do các chuyên gia: Jeff Wilcox, Thomas Claudius Huber, Kevin Marshall, Stephanie Hertrich … xây dựng […]

    December 29, 2012 at 6:05 am
  • Aby V John Reply

    It is just awesome!!!!!!!!!

    March 1, 2013 at 8:25 am
  • Aby V John Reply

    Thanks a lot man!!!!!!

    March 1, 2013 at 8:26 am
  • Abhilash Reply

    Thanks. Helped a lot :)

    April 20, 2013 at 10:14 am
  • xaero Reply

    Thanks it’s very nice

    August 7, 2013 at 10:45 am
  • Terry Reply

    This is fixed in SL 5. The default value remains LostFocus, but the enumeration now contains PropertyChanged as well, wo working in SL 5 doesn’t require this workaround anymore.

    August 12, 2013 at 8:56 am
    • Jamie Reply

      Actually, the SL5 UpdateSourceTrigger=PropertyChanged does not always work. I had a TextBox in a DataGridTemplateColumn with UpdateSourceTrigger=PropertyChanged. I found that when entering edit mode by clicking a cell in this column, the source was updated after each character as expected. However, if edit mode was entered by tabbing from an adjacent cell, the UpdateSourceTrigger reverted to LostFocus. Thomas’ code solved this problem for me. Many thanks.

      February 16, 2018 at 9:14 am

Leave a Reply to John Cancel reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.