2

I am trying to attach a command and a commandparameter to a textbox on return key but without success. The parameter is the current text in the same textbox.

<TextBox x:Name="txtSearch">
    <TextBox.InputBindings>
         <KeyBinding  Command="{Binding SearchCommand}" 
                      CommandParameter="{Binding Path=Text, ElementName=txtSearch}" Key="Return" />
    </TextBox.InputBindings>
</TextBox>

Basically I want to execute the command when user clicks on return/enter key and pass as a parameter the current text in the textbox.

I have found this link where it is said that in .NET 3.5 command parameter for keybinding is not accepting bindings. So a solution is proposed by code in code-behind but how can I pass a parameter to the command from the code?

4

1 回答 1

2

首先,您需要将 KeyBinding 添加到 TextBox 并将其 Command 设置为代码隐藏。只需在视图的构造函数中添加它:

public MainWindow()
{
    InitializeComponent();
    DataContext = new MyViewModel();

    KeyBinding kb = new KeyBinding();
    kb.Command = (DataContext as MyViewModel).SearchCommand;                        
    kb.Key = Key.Enter;
    txtSearch.InputBindings.Add(kb);
}

然后,您可以将Text命名txtSearch为 TextBox 的属性绑定到您的 ViewModel 的属性。这样您就不需要传递参数,因为您可以在执行命令的代码中的 ViewModel 中使用该属性的值。

您的 ViewModel 应如下所示:

public class MyViewModel : ObservableObject
{
    private string _txtSearch;
    public string TxtSearch
    {
        get { return _txtSearch; }
        set
        {
            if (value != _txtSearch)
            {
                _txtSearch = value;
                OnPropertyChanged("TxtSearch");
            }
        }
    }

    private ICommand _searchCommand;
    public ICommand SearchCommand
    {
        get
        {
            if (_searchCommand == null)
            {
                _searchCommand = new RelayCommand(p => canSearch(), p => search());
            }
            return _searchCommand;
        }
    }
    private bool canSearch()
    {
        //implement canExecute logic.
    }
    private void search()
    {
        string text = TxtSearch; //here you'll have the string that represents the text of the TextBox txtSearch
        //DoSomething
    }
}

如果您有权访问 C# 6(Visual Studio 2015 和更高版本),则可以将对 OnPropertyChanged 的​​调用更改为:OnPropertyChanged(nameof(TxtSearch));。这样您就可以摆脱“魔术字符串”,并且最终重命名属性不会给您带来任何问题。

然后您的 XAML 应该如下所示:(请注意,您需要指定 te UpdateSourceTrigger 必须是 PropertyChanged,以便您的 ViewModel 的属性在您按下TextBox 上TxtSearch的键时保持最新。Enter

<TextBox Text="{Binding TxtSearch, UpdateSourceTrigger=PropertyChanged}" x:Name="txtSearch"/>    

您的 ViewModel 需要实现 INotifyPropertyChanged 并且您需要正确的 ICommand 实现。在这里,我将使用 RelayCommand。

这些实现如下所示。

由于您的框架是 .NET 3.5,因此像这样实现它:

public class ObservableObject : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

这是 RelayCommand 的实现:

public class RelayCommand : ICommand
{
    private Predicate<object> _canExecute;
    private Action<object> _execute;

    public RelayCommand(Predicate<object> canExecute, Action<object> execute)
    {
        _canExecute = canExecute;
        _execute = execute;
    }

    public bool CanExecute(object parameter)
    {
        return _canExecute(parameter);
    }

    public void Execute(object parameter)
    {
        _execute(parameter);
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }
}
于 2017-08-02T13:05:53.760 回答