Silverlight TextBox AutoComit Behaviour

Standard Silverlight TextBox control is very useful but has one strange behavior: if you use TwoWay data binding and bind some property to controls Text property, when users type text into the control, this change is not propagated to the bound property until the control loses its focus.  

This can be very annoying if you have MVVM application and you have some kind of real-time filter that needs to update some data as-you-type.  

In TwoWay bindings, changes to the target automatically update the source, except when binding to the Text property of a TextBox. In this case, the update occurs when the TextBox loses focus (in case of element to element binding the text box behaviour is normal) .  

You can disable automatic source updates and update the source at times of your choosing. For example, you can do this to validate user input from multiple controls before you update the bound data sources.  

You must update the source for each binding individually, however. To update a binding, first call the FrameworkElement.GetBindingExpression method of a target element, passing in the target DependencyProperty. You can then use the return value to call the BindingExpression.UpdateSource method. The following example code demonstrates this process  

 Problem is that TextBox control does not call BindingExpression.UpdateSource when its Text property is changed so we have to do that manually in order to fix this issue.The AutoComit Behavior for textbox control is now part of NanoVMSupport Library (Lib for MVVM)  

public class AutoCommit : Behavior<TextBox>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.TextChanged += AssociatedObjectOnTextChanged;
    }

    private void AssociatedObjectOnTextChanged(object sender, TextChangedEventArgs args)
    {
        var bindingExpr = AssociatedObject.GetBindingExpression(TextBox.TextProperty);
        if(bindingExpr != null) bindingExpr.UpdateSource();
    }

    protected override void OnDetaching()
    {
        AssociatedObject.TextChanged -= AssociatedObjectOnTextChanged;
        base.OnDetaching();
    }
}

And the xaml is  

<TextBox Text=”{Binding SearchText,Mode=TwoWay}”> 
 <i:Interaction.Behaviors> 
<NanoVM:AutoCommit/> 
</i:Interaction.Behaviors> 
</TextBox> 

Another approach to solve this issue is to create TextBoxEx class drived from TextBox.With this approach the xaml size will be highly reduced as for each text box in your application it would save around 90 chars in xaml.

public class TextBoxEx : TextBox
{
    public TextBoxEx()
    {
        this.Loaded += new RoutedEventHandler(TextBoxEx_Loaded);
    }

    void TextBoxEx_Loaded(object sender, RoutedEventArgs e)
    {
        this.TextChanged += new TextChangedEventHandler(TextBoxEx_TextChanged);
    }

    void TextBoxEx_TextChanged(object sender, TextChangedEventArgs e)
    {
        var source = sender as TextBox;
        if (source != null)
        {
            var bindingExpression = source.GetBindingExpression(TextBox.TextProperty);
            if (bindingExpression != null)
            {
                bindingExpression.UpdateSource();
            }
        }
    }

}

and xaml in this case is 

<ctrls:TextBoxEx Text=”{Binding SearchText,Mode=TwoWay}”/>

However the above behaviour give you more control of how text box behaves.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s