Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
155 views
Welcome To Ask or Share your Answers For Others

1 Answer

The RelayCommand class in MvvmLight has two implementations. In the GalaSoft.MvvmLight.Command namespace and in the GalaSoft.MvvmLight.CommandWpf namespace.

You've probably used from namespace GalaSoft.MvvmLight.Command. And this type doesn't actually update the state of the command.

If used from the GalaSoft.MvvmLight.CommandWpf namespace, then the state of the command is updated according to the predetermined logic.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...