How to pass the updated text by CommandParameter in TextChagned event?

1.7k Views Asked by At

This is an interesting case. I use MVVMLight to catch the event TextChagned of a textbox and pass it to a command in ViewModel and somehow the text value passed by CommandParameter is still the old text before the update. Anyone knows how to get the new text?

<Grid>
    <TextBox x:Name="myTextBox" HorizontalAlignment="Left" 
             Height="23" Margin="10,10,0,0" TextWrapping="Wrap" Text="Hello" 
             VerticalAlignment="Top" Width="120">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="TextChanged">
                <cmd:EventToCommand Command="{Binding Mode=OneWay,Path=TextChangedCommand}" 
                                    PassEventArgsToCommand="True"
                                    CommandParameter="{Binding Path=Text,ElementName=myTextBox}"/>
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </TextBox>
    <Button Content="Button" HorizontalAlignment="Left" Margin="352,214,0,0" 
            VerticalAlignment="Top" Width="75" Click="Button_Click"/>




</Grid>

enter image description here

public class MainViewModel : ViewModelBase
{
    /// <summary>
    /// Initializes a new instance of the MainViewModel class.
    /// </summary>
    public MainViewModel()
    {
        ////if (IsInDesignMode)
        ////{
        ////    // Code runs in Blend --> create design time data.
        ////}
        ////else
        ////{
        ////    // Code runs "for real"
        ////}
    }

    private RelayCommand<string> _textChangedCommand;

    public RelayCommand<string> TextChangedCommand
    {
        get 
        {
            if (this._textChangedCommand == null)
            {
                this._textChangedCommand = new RelayCommand<string>(this.TextChanged);
            }
            return this._textChangedCommand; 
        }
    }

    private void TextChanged(string input)
    {
        MessageBox.Show(input);
    }

}

1

There are 1 best solutions below

2
On BEST ANSWER

I was digging into the code of MVVM Light and in EventToCommand.cs's Invoke method it seems that the parameter still has its old value. I didn't look further, but maybe this is a bug in MVVM.

There is a workaround you can do though.

Create a new class implementing IEventArgsConverter, something similar to this:

public class TextChangedEventArgsConverter : IEventArgsConverter
{
    public object Convert(object value, object parameter)
    {
        var textChangedEventArgs = (TextChangedEventArgs) value;
        return ((TextBox) textChangedEventArgs.Source).Text;
    }
}

Add it to the Resources collection of your Window or ResourceDictionary where you have the EventToCommand that's not working.

<Window.Resources>
    <textChanged:TextChangedEventArgsConverter x:Key="TextChangedEventArgsConverter" />
</Window.Resources>

And change the EventToCommand to the following:

<cmd:EventToCommand Command="{Binding Mode=OneWay,Path=TextChangedCommand}" 
                    PassEventArgsToCommand="True"
                    EventArgsConverter="{StaticResource TextChangedEventArgsConverter}" />

So the specified EventArgsConverter will receive the actual TextChangedEventArgs and will extract the Text itself, which will be the correct value.

With these changes, I was able to achieve what you are looking for.

Desired result

By the way: don't use CommandParameter and PassEventArgsToCommand="True" at the same time. As the documentation says, if you are setting PassEventArgsToCommand to true, the type parameter of your RelayCommand should be the event argument type of the event which is TextChangedEventArgs in this case.