InvokeCommandAction CommandParameter始终为零

时间:2018-11-08 09:57:10

标签: c# wpf mvvm

背景:我正在尝试根据文本框是否选择了文本来启用和禁用命令。

根据我的研究,我需要使用事件触发器。这个问题所涉及的InvokeCommandAction或由于某种原因在我的系统上不存在的InvokeMethodAction。

问题:我已经按照以下步骤设置了该程序。它运行,命令启动,但参数始终为零。

<Window x:Class="LogWpfApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
        xmlns:local="clr-namespace:LogWpfApp"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:ViewModel />
    </Window.DataContext>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Button Grid.Row="0" Grid.Column="0" Content="Copy" HorizontalAlignment="Left" Margin="0,0,0,0" VerticalAlignment="Top" Width="75"
                Command="{Binding CmdCopy}" CommandTarget="{Binding ElementName=textBoxNote}" CommandParameter="{Binding ElementName=textBoxNote}"/>
        <Button Grid.Row="0" Grid.Column="1" Content="Paste" HorizontalAlignment="Left" Margin="0,0,0,0" VerticalAlignment="Top" Width="75"
                />
        <TextBox x:Name="textBoxNote" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Margin="0,0,0,0" TextWrapping="Wrap"
                 Text="{Binding Note}">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="SelectionChanged">
                    <i:InvokeCommandAction Command="{Binding CmdSelectionLengthChanged}" CommandParameter="{Binding ElementName=textBoxNote, Path=SelectionLength}" />
                    <i:InvokeCommandAction Command="{Binding CmdSelectionStartChanged}" CommandParameter="{Binding ElementName=textBoxNote, Path=SelectionStart}" />
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </TextBox>
        <Label Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Content="{Binding Clipboard}"/>
    </Grid>
</Window>

这是ViewModel:

public class ViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private RelayCommand<TextBox, TextBox> cmdCopy;
    private RelayCommand<object, object> cmdPaste = new RelayCommand<object, object>(foo => { }, (tb) => { return true; });
    private RelayCommand<int, int> cmdSelectionLengthChanged;
    private RelayCommand<int, int> cmdSelectionStartChanged;
    private String note = "This is some default initial text";
    private String clippboard = "";
    private int selectionLength = 0;
    private int selectionStart = 0;



    public ViewModel()
    {
        cmdCopy = new RelayCommand<TextBox, TextBox>(
            tb => { clippboard = tb.SelectedText; },
            tb => { return SelectionLength > 0; /* tb != null && tb.SelectionLength > 0;*/ }
        );

        cmdSelectionLengthChanged = new RelayCommand<int, int>(
            length => {
                Console.WriteLine("New SelectionLength {0}", length);
                SelectionLength = length; cmdCopy.FireCanExecuteChanged(); },
            foo => { return true; }
        );

        cmdSelectionStartChanged = new RelayCommand<int, int>(
            start => {
                Console.WriteLine("New SelectionStart {0}", start);
                selectionStart = start; },
            foo => { return true; }
        );
    }



    public RelayCommand<TextBox, TextBox> CmdCopy => cmdCopy;
    public RelayCommand<object, object> CmdPaste => cmdPaste;
    public RelayCommand<int, int> CmdSelectionLengthChanged => cmdSelectionLengthChanged;
    public RelayCommand<int, int> CmdSelectionStartChanged => cmdSelectionStartChanged;


    public String Note
    {
        get { return note; }
        set
        {
            if (this.note != value)
            {
                this.note = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Note)));
            }
        }
    }

    public String Clipboard
    {
        get { return clippboard; }
        private set
        {
            if (clippboard != value)
            {
                clippboard = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Clipboard)));
            }
        }
    }

    public int SelectionLength
    {
        get { return selectionLength; }
        set
        {
            if (selectionLength != value)
            {
                selectionLength = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SelectionLength)));
            }
        }
    }
}

1 个答案:

答案 0 :(得分:0)

SelectionLengthSelectionStart都不是在设置通知时会发出通知的依赖项属性。这意味着命令参数的值将始终具有0的初始值。

如果您绑定到TextBox本身:

<i:InvokeCommandAction Command="{Binding CmdSelectionLengthChanged}" CommandParameter="{Binding ElementName=textBoxNote}" />

...您将可以通过在Execute方法中显式查询属性来检索值:

cmdSelectionLengthChanged = new DelegateCommand<TextBox, TextBox>(
    textBox => {
                   Debug.WriteLine("New SelectionLength {0}", textBox.SelectionLength);
               },
    foo => { return true; }
);