tags:

views:

2684

answers:

5

I am following the M-V-VM pattern for my WPF UI. I would like to hook up a command to the TextChanged event of a TextBox to a command that is in my ViewModel class. The only way I can conceive of completing this task is to inherit from the TextBox control, and implement ICommandSource. I can then instruct the command to be fired from the TextChanged event. This seems to be too much work for something which appears to be so simple.

Is there an easier way (than subclassing the TextBox and implementing ICommandSource) to hook up the TextChanged event to my ViewModel class?

+1  A: 

I may not have understood the problem correctly but here goes..

  1. Handle TextBox.TextChanged event and call a ViewModel method.
  2. ViewModel subscribes to TextBox.TextChanged event
  3. More work but the most loosely coupled of the lot.

First define a custom command

public class MyAppCommands
{
  public static RoutedUICommand X_ChangedCommand;
  static MyAppCommands()
  {
    X_ChangedCommand = new RoutedUICommand("X_Changed", "X_Changed", typeof(MyAppCommands);
  }
}

Next in the View

<Textbox Command="myNs:MyAppCommands.X_Changed"> Some Text </TextBox>

The top level / ancestor UI / listener simply has to indicate that he wishes to handle this command like this
In the ctor of ParentWindow()

 CommandBinding cb = new CommandBinding(MyAppCommands.X_Changed);
 cb.Executed += new ExecutedRoutedEventHandler(What_I_Want_To_Do_When_This_Happens);
 this.CommandBindings.Add(cb);

If its a non-UI class I think there is a RoutedCommand equivalent of the RoutedUICommand. But the pattern should be the same. HTH

Gishu
+1  A: 

Can you not just handle the TextChanged event and execute the command from there?

private void _textBox_TextChanged(object sender, EventArgs e)
{
    MyCommand.Execute(null);
}

The alternative, as you say, is to create a TextBox that acts as a command source, but that does seem like overkill unless it's something you're planning on sharing and leveraging in many places.

HTH, Kent

Kent Boogaart
+5  A: 

First off, you've surely considered two-way data binding to your viewmodel, with an UpdateSourceTrigger of PropertyChanged? That way the property setter of the property you bind to will be called every time the text is changed?

If that's not enough, then I would tackle this problem using Attached Behaviours. On Julian Dominguez’s Blog you'll find an article about how to do something very similar in Silverlight, which should be easily adaptable to WPF.

Basically, in a static class (called, say TextBoxBehaviours) you define an Attached Property called (perhaps) TextChangedCommand of type ICommand. Hook up an OnPropertyChanged handler for that property, and within the handler, check that the property is being set on a TextBox; if it is, add a handler to the TextChanged event on the textbox that will call the command specified in the property.

Then, assuming your viewmodel has been assigned to the DataContext of your View, you would use it like:

<TextBox x:Name="MyTextBox" TextBoxBehaviours.TextChangedCommand="{Binding ViewModelTextChangedCommand}" />
Samuel Jack
Thanks Sam - sometimes I fail see the simple options; which in this case was having the textbox bound to a string property in my ViewModel.
Brad Leach
I don't think that adding logic to the setter of the property would work. The WPF XAML processor uses the dependency property directly rather than going through the property wrapper. This means that the setter will never be called when the UI is updated. (source: http://msdn.microsoft.com/en-us/library/bb613563.aspx)
Greg
Greg, I'm referring to the Setter of the property in the ViewModel to which the dependency property is bound, not the setter of the dependency property itself.
Samuel Jack
+1  A: 

Using the event binding and command method might not be the right thing to use. What exactly will this command do?

You might want to consider using a Databinding to a string field in your VM. This way you can make a call to a command or function from there rather than having the UI care at all.

<TextBox Text="{Binding WorldName}"/>
....
public string WorldName
{
    get
    {
        return WorldData.Name;
    }
    set
    {
        WorldData.Name = value;
        OnPropertyChanged("WorldName");
        // CallYourCustomFunctionHere();
    }
}
Nidonocu
Thanks Nidonocu. Your answer is also perfect, but I marked Sam's response as the answer because he answered slightly before yours. Thanks again though!
Brad Leach
A: 

How can you do this if your objects are bound to an RIA Entity object? If so then you can't intercept in the property like above.

Brandon