Description
In WPF, using MvvmLight, I have a viewModel with an integer property SelectedIndex
. Changing the value of this property is an expensive operation, so I only want to update the property if the operator is fairly certain that he finished typing.
I have a TextBox and a button. The operator types a number, and presses the button. This should lead to a command that updates the property.
Standard WPF MvvmLight solution for this
class MyViewModel
{
private int selectedIndex;
public MyViewModel()
{
this.CommandSelectIndex = new RelayCommand(ExecuteSelectIndex, CanSelectIndex);
}
public public RelayCommand<int> CommandSelectIndex { get; }
public int SelectedIndex
{
get => this.selectedIndex;
set => base.Set(nameof(SelectedIndex), ref this.selectedIndex, value);
}
private bool CanSelectIndex(int proposedIndex)
{
return proposedIndex > 0 && proposedIndex < MyData.Count;
}
private void ExecuteSelectIndex(int proposedIndex)
{
this.SelectedIndex = proposedIndex;
ProcessSelectedIndex(proposedIndex); // Expensive!
}
}
For those who know MvvmLight, this is fairly straightforward.
So while the operator is typing a number, I only want to update the button. I don't want to do anything with the intermediate values:
1 --> 12 --> 123 --> (typing error, backspace) --> 124 [press button]
XAML
<StackPanel Name="Test1" Orientation="Horizontal">
<TextBox Name="ProposedValue1" Text="1234" Width="300" Height="20"/>
<Button x:Name="ButtonChangeText1" Content="Change"
Height="30" Width="74" Padding="5,2"
Command="{Binding Path=CommandSelectedIndex}"
CommandParameter="{Binding ElementName=ProposedValue1, Path=Text}"/>
</StackPanel>
This works partly: at startup CanSelectIndex(1234)
is called; If the button is pressed ExecuteSelectedIndex(1234)
is called.
Problem
However, if the text of the TextBox changes, CanSelectIndex is not called.
The reason is because event ICommand.CanExecuteChanged
is not raised when the textbox changes.
Solution:
Add an event handler:
XAML:
<TextBox Name="ProposedValue1" Text="1234" Width="300" Height="20"
TextChanged="textChangedEventHandler"/>
Code behind:
private void textChangedEventHandler(object sender, TextChangedEventArgs args)
{
((MyViewModel)this.DataContext).CommandSelectedIndex.RaiseCanExecuteChanged();
}
I always feel a bit uneasy whenever I have to write code behind. Is it standard to write eventhandlers in code behind, or is that a simplification that I only see in tutorials.
Is there a method that I can do this in XAML? Something with Binding?
TextChanged="TextChanged="{Binding Path=CommandSelectIndex ??? RaiseCanExecuteChanged() }
See Question&Answers more detail:os