Say I have a WPF TextBox
:
<TextBox Text="{Binding Foo}" />
Is there a way to execute some ICommand
after the property Foo
is updated by the TextBox
(i.e. is updated specifically by the TextBox
rather than some other control or code)?
I don't want to use the SourceUpdated event of the binding because I want to avoid "code-behind".
You can try making a method that does whatever you want to be done and call that method after the raisepropertychanged() is called. For example
public void MyMethod()
{
//Do whatever;
}
And then in your property getter setter:
public string MyText
{
get { return _MyText; }
set
{
_MyText = value;
RaisePropertyChanged("MyText")
// THen call that method
MyMehtod();
}
}
Syntax may be off, I'm use to doing vb lately. Hope this helps, there are other ways though if you need other options.
Edit 2:
<Textbox Text="{Binding Foo}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="TextChanged">
<i:InvokeCommandAction Command="{Binding TextChangedCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
Where TextChangedCommand is in your viewmodel
Not sure if TextChanged is an EventName, I dont memorize all the available event types
You do realise the MVVM police won't come and get you if do end up having some code behind? Using event to command etc is essentially just coding in XAML instead of in C# anyway. Either way you need to hook an event up to a command because the control doesn't expose a command for what you are after.
I think this is what you after, let me know if I'm on the wrong track:
You want to know when the update to Foo comes from the textbox and the textbox only. i.e. if the update to Foo comes from some code you don't want the command to run, correct?
If so:
<TextBox Name="Fred" Text="{Binding Foo, NotifyOnSourceUpdated=True}" SourceUpdated="Fred_SourceUpdated"/>
Then in the "evil" code behind have:
private void Fred_SourceUpdated(object sender, DataTransferEventArgs e)
{
}
In that method you can cast the datacontext of the view into the viewmodel and call whatever command you want. The source updated event will not get called if something else updates Foo.
If you really want to not have code behind as you mention in your OP then you could do an attached behaviour but that is massive overkill for a "nonsense" requirement. The fact that you logic depends on the whether or not the change comes from the textbox means that your view is more than a view already. This approach still allows you to have your command code fully testable in you VM.
2nd edit
You could also look at using the source updated event in XAML via the event to command rather than text changed
Assuming you have implemented INotifyPropertyChanged
, you just need to handle the PropertyChanged
event. You execute the command in your event handler. This event handler goes in your ViewModel (not your code behind).
Edit
Here is an example of how the EventToCommand behavior in MVVM Light works. You can use this allow any event to be handled with a command.
<Rectangle Fill="White"
Stroke="Black"
Width="200"
Height="100">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseEnter">
<cmd:EventToCommand Command="{Binding TestCommand,
Mode=OneWay}"
CommandParameter="{Binding Text,
ElementName=MyTextBox,
Mode=OneWay}"
MustToggleIsEnabledValue="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Rectangle>
Edit 2
Another idea would be to always use a method when changing Foo
via code. This way, you know that any change to Foo
that doesn't use the method must have been changed by the user.
private bool _isFooUpdating;
private void SetFoo(string value)
{
_isFooUpdating = true;
Foo = value;
_isFooUpdating = false;
}
public string Foo
{
get { return _foo; }
set
{
if (_foo = value) return;
_foo = value;
OnFooChanged();
OnPropertyChanged("Foo");
}
}
private void OnFooChanged()
{
if (_isFooUpdating) return;
FooChangedCommand.Execute();
}