James Fassett
James Fassett

Reputation: 41064

Call a command on a view model whenever any TextBox in the view changes

I have a few views that each have several XAML TextBox instances. The Text property of each is bound to a value object that represents the visual data model for the view.

<TextBox Text="{Binding Path=SelectedItem.SomeValue, UpdateSourceTrigger=PropertyChanged}"/>

I have about 9 or 10 of these boxes in a form. I have a class (ChangeModel) that keeps track of which forms have been altered (e.g. the user has entered in a new value). The problem is the actual value object that is bound to the TextBox.Text property (in the example that would be SelectedItem.SomeValue) can't access the ChangeModel.

I'd like to easily add a binding in the XML (maybe in the resources section) that will call a command in the view model whenever any TextBox changes. I think I can do this with a DataTrigger statement but I'm not sure how to go about it.

Can anyone describe how to use a data trigger or any other XAML mechanism to alert the view model whenever any TextBox within that view is altered?

Upvotes: 1

Views: 286

Answers (1)

hival
hival

Reputation: 675

Alternatively to that Markus Hütter said you can save a few lines of XAML and write custom behavior like this

public class InvokeCommandOnTextChanged : Behavior<TextBox>
{
    public static DependencyProperty CommandProperty =
        DependencyProperty.Register("Command", typeof(ICommand), typeof(InvokeCommandOnTextChanged));

    public static DependencyProperty CommandParameterProperty =
        DependencyProperty.Register("CommandParameter", typeof(object), typeof(InvokeCommandOnTextChanged));

    public ICommand Command
    {
        get { return (ICommand)GetValue(CommandProperty); }
        set { SetValue(CommandProperty, value); }
    }

    public object CommandParameter
    {
        get { return GetValue(CommandParameterProperty); }
        set { SetValue(CommandParameterProperty, value); }
    }

    protected override void OnAttached()
    {
        base.OnAttached();
        this.AssociatedObject.TextChanged += OnTextChanged;
    }

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

    private void OnTextChanged(object sender, TextChangedEventArgs e)
    {
        var command = this.Command;
        var param = this.CommandParameter;

        if (command != null && command.CanExecute(param))
        {
            command.Execute(param);
        }
    }
}

Then you can use this behavior with your textboxes:

<TextBox>
    <i:Interaction.Behaviors>
        <b:InvokeCommandOnTextChanged Command="{Binding AddCommand}" />
    </i:Interaction.Behaviors>
</TextBox>

Upvotes: 1

Related Questions