Home > C#, WinRT > How to immediately update the source of a TextBox in WinRT with C#

How to immediately update the source of a TextBox in WinRT with C#

14/03/2013

The TextBox control in WinRT lacks the UpdateSourceTrigger property. So, if we bind its Text property to a property of our ViewModel, specifying the Mode=TwoWay attribute, the only behavior we can obtain is that our property will be updated when the TextBox loses focus.

If, instead, we need an immediate update, one possibile solution is to create a class that extends the standard TextBox and handles the TextChanged event to explicitly update the source:

public class ImmediateUpdateSourceTextBox : TextBox
{
    public static readonly new DependencyProperty TextProperty =
        DependencyProperty.Register("Text", typeof(string),
        typeof(ImmediateUpdateSourceTextBox),
        new PropertyMetadata(default(string), OnTextChanged));

    private static void OnTextChanged(DependencyObject d,
        DependencyPropertyChangedEventArgs e)
    {
        var txt = d as TextBox;
        txt.Text = (string)e.NewValue;
    }

    public new string Text
    {
        get { return (string)GetValue(TextProperty); }
        set { SetValue(TextProperty, value); }
    }

    public ImmediateUpdateSourceTextBox()
    {
        base.TextChanged += (s, e) =>
        {
            Text = base.Text;
        };
    }
}

However, this approach requires to substitute every TextBox for which we want this behavior with the new extended control.

Another solution involves the use of attached properties:

public class ImmediateSourceUpdate : DependencyObject
{
    public static readonly DependencyProperty IsEnabledProperty =
        DependencyProperty.RegisterAttached("IsEnabled", typeof(bool), 
        typeof(ImmediateSourceUpdate),
        new PropertyMetadata(false, OnIsEnabledChanged));

    public static bool GetIsEnabled(DependencyObject obj)
    {
        return (bool)obj.GetValue(IsEnabledProperty);
    }

    public static void SetIsEnabled(DependencyObject obj, bool value)
    {
        obj.SetValue(IsEnabledProperty, value);
    }

    private static void OnIsEnabledChanged(DependencyObject d, 
        DependencyPropertyChangedEventArgs e)
    {
        var txt = d as TextBox;
        if (txt != null)
        {
            if ((bool)e.NewValue)
                txt.TextChanged += txt_TextChanged;
            else
                txt.TextChanged -= txt_TextChanged;
        }
    }

    public static readonly DependencyProperty SourceProperty =
        DependencyProperty.RegisterAttached("Source", typeof(string), 
        typeof(ImmediateSourceUpdate), 
        new PropertyMetadata(default(string)));  
    
    public static string GetSource(DependencyObject d)
    {
        return (string)d.GetValue(SourceProperty);
    }

    public static void SetSource(DependencyObject d, string value)
    {
        d.SetValue(SourceProperty, value);
    }

    private static void txt_TextChanged(object sender, TextChangedEventArgs e)
    {
        var txt = sender as TextBox;
        txt.SetValue(ImmediateSourceUpdate.SourceProperty, txt.Text);
    }
}

Having this class, we can write something like this:

<TextBox Text="{Binding Content}" 
        helpers:ImmediateSourceUpdate.IsEnabled="True"
        helpers:ImmediateSourceUpdate.Source="{Binding Content, Mode=TwoWay}" />

When we set the IsEnabled attached property of ImmediateSourceUpdate to true, we register on the TextChanged event of the TextBox. In its event handler, we update the Source property. Because it is in two-way binding with the property of our model, the latter is immediately updated, so that we’ll obtain the desired behavior.

This solution doesn’t require to change the existing XAML objects (we only add attached properties), but the drawback is that we need to specify the binding two times.

Categories: C#, WinRT
  1. Edu
    15/03/2013 at 03:36

    great!

  2. 06/05/2013 at 05:32

    Thank you, it helped a lot🙂

  1. No trackbacks yet.
Comments are closed.
%d bloggers like this: