An attached behavior for TextBoxes to support TextChanged commands

Recently I was working on an MVVM demo for an article where I wanted live filtering based on the contents of a text box. The problem with this is that the TextBox does not have a Command property, and thus I’d need to use code-behind to proxy its text changed event to the ViewModel. And I did not want to do that. This was purely whimsical behavior on my part since MVVM does not mandate this at all, though a lot of people do recommend it. Apparently, you can get around this by referencing an Expression Blend DLL, which has support for interaction triggers that you can forward to a command object, thereby avoiding any code-behind. I didn’t want to reference an Expression Blend DLL, not for a simple demo app anyway and so I was forced to work around it by adding an attached behavior to the TextBox that could take a command object. This was a bit of an over-kill of course, and in a real world app I’d simply do it in code-behind. Most likely something like :

ViewModel viewModel = this.DataContext as ViewModel;

. . .

private void TextChanged(. . .)
{
    viewModel.SomeCommand(. . .) ;
}

That’d be in my view’s code-behind, and while some purists may not be too happy, I think it’s definitely simpler than referencing Expression Blend! Here’s what a typical Xaml code snippet using this behavior would be like:

<TextBox x:Name="searchTextBox" Width="165"
  HorizontalAlignment="Left" Margin="3,0,0,0"
  Text="{Binding SearchText}"
  local:TextChangedBehavior.TextChanged="{Binding FilterCommand}" />

Instead of handling the TextChanged event, I handle it via the attached behavior and route it to the FilterCommand command object in the ViewModel. Here’s the code for the attached behavior:

internal class TextChangedBehavior
{
    public static DependencyProperty TextChangedCommandProperty
        = DependencyProperty.RegisterAttached(
          "TextChanged",
          typeof(ICommand),
          typeof(TextChangedBehavior),
          new FrameworkPropertyMetadata(
            null,
            new PropertyChangedCallback(
              TextChangedBehavior.TextChangedChanged)));

    public static void SetTextChanged(TextBox target, ICommand value)
    {
        target.SetValue(TextChangedBehavior.TextChangedCommandProperty,
          value);
    }

    public static ICommand GetTextChanged(TextBox target)
    {
        return (ICommand)target.GetValue(TextChangedCommandProperty);
    }

    private static void TextChangedChanged(
      DependencyObject target, DependencyPropertyChangedEventArgs e)
    {
        TextBox element = target as TextBox;

        if (element != null)
        {
            if (e.NewValue != null)
            {
                element.TextChanged += Element_TextChanged;
            }
            else
            {
                element.TextChanged -= Element_TextChanged;
            }
        }
    }

    static void Element_TextChanged(object sender, TextChangedEventArgs e)
    {
        TextBox textBox = (TextBox)sender;
        BindingExpression bindingExpression = textBox.GetBindingExpression(
          TextBox.TextProperty);

        if (bindingExpression != null)
        {
            bindingExpression.UpdateSource();
        }

        ICommand command = GetTextChanged(textBox);

        if (command.CanExecute(null))
        {
            command.Execute(null);
        }
    }
}

Nothing complicated there, just a basic attached behavior implementation.

Advertisements

One thought on “An attached behavior for TextBoxes to support TextChanged commands

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 )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s