wpf - 双击 WPF ListView - 如何触发命令而不使用事件处理程序

标签 wpf mvvm

我对如何在我的特定情况下将事件实现为命令感到有些困惑。我想尊重 MVVM,但在这种情况下不知道怎么做。

我有一个 WPF ' View ' - viewCustomerSearch。这上面有一些文本框,当用户单击“搜索”时,结果会填充到 ListView 中。 viewCustomerSearch 绑定(bind)到 viewmodelCustomerSearch,效果很好。

viewCustomerSearch 托管在 viewCustomer 上。

我想知道 viewCustomerSearch 公开一个自定义命令 - CustomerSelectedCommand - 每当双击 viesCustomerSearch 中的 ListView 时“触发”,然后由 viewCustomer 后面的 View 模型(即 viewmodelCustomer)处理。这似乎正确实现了理论上的 MVVM 模式。

我将主要问题分解为三个较小的问题,但希望您能看到它们都是同一个挑战的组成部分。

第一个问题 :为了让 viewCustomerSearch 公开一个自定义命令,我似乎必须将此代码放入 viewCustomerSearch - 这似乎“破坏”了 MVVM(后面的 View 代码中没有代码)。

public readonly DependencyProperty CustomerSelectedCommandProperty = DependencyProperty.Register("CustomerSelectedCommand", typeof(ICommand), typeof(viewCustomerSearch));

public ICommand CustomerSelectedCommand
{
    get { return (ICommand)GetValue(CustomerSelectedCommandProperty); }
    set { SetValue(CustomerSelectedCommandProperty, value); }
}

第二个问题 (这是真正让我感动的一个):最好通过展示我会做什么来破坏 MVVM 来解释。我会在 View 中有一个事件处理程序:
private void lstResults_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
    if (CustomerSelectedCommand != null) CustomerSelectedCommand.Execute(((ViewModels.viewmodelCustomerSearchResult)this.lstResults.SelectedItem).CustomerId);
}

嗯......我知道你不应该把这个事件处理程序放在这里;相反,它应该有一个命令来在 viewmodelCustomerSearch 中处理它。这里的两个问题是
  • 因为“CustomerSelectedCommand”ICommand 是在
    viewCustomerSearch,viewmodelCustomerSearch 看不到它来触发它。
  • 我看不到如何将 MouseDoubleClick 事件绑定(bind)到命令,而不是后面的 View 代码中的事件处理程序。我正在阅读有关附加属性的信息,但看不到如何在此处应用它们。

  • (请注意:我在应用程序的其他地方使用通用的“RelayCommand”;这在这里起作用吗??)

    第三个问题 :当我在事件处理程序后面的代码中使用非 MVVM 方式触发命令时,您可以看到我将 Selected Customer Id 作为参数传递给命令。如何在 viewCustomer 的命令处理程序中看到该参数?我创建了一个新的 RelayCommand 来处理它,但似乎 Execute 方法不接受参数?

    鉴于以上所有情况,我不得不说我个人并不赞同“MVVM 意味着 View 中没有代码”。这对我来说似乎很疯狂;完全与 View 有关的代码,并且仅与 View 有关,恕我直言,不应进入 View 模型。尽管如此,这看起来确实像逻辑上的东西(不是 View 的东西)。

    非常感谢您的一些见解。对不起,很长的帖子;试图平衡足够的信息来帮助我处理“ war 与和平”。

    DS

    最佳答案

    在您的 View 中,您可以在 xaml 中添加“命令”属性并将其绑定(bind)到 ViewModel 的命令

    Command="{Binding CustomerSelectedCommand}"
    

    参数可以通过多种方式传递。大多数时候,我只是将其他项目绑定(bind)到我的 ViewModel,我可以直接使用它们。但是,还有一个名为 CommandParameter 的属性,这是在 XAML 中指定它的示例。
     CommandParameter="{Binding ElementName=txtPassword}"
    

    然后在我的 ViewModel 中,我的 Command 的定义如下所示
    private void UserLogonCommandExecute(object parameter)
    {
    ...
           var password_box = parameter as PasswordBox;
    ...
    }
    

    听起来您已经知道如何在 ViewModel 中设置 RelayCommand,所以我不会深入讨论。我找到了How Do I: Build Data-driven WPF Application using the MVVM pattern在我开始时很有帮助。

    Per Comment Request 命令属性示例

    我只是要获取一些工作代码,这是在 XAML 中将 Command 属性添加到按钮的方法。
    <Button Command="{Binding ConnectCommand}">
    //Your button content and closing </Button> here
    

    这假设您已将 DataContext 设置为具有名为 ConnectCommand 的命令的 ViewModel。这是 ConnectCommand 的示例。您需要将 ConnectCommandCanExecute 和 ConnectCommandExecute 的内容替换为您想要完成的任何工作。
    public ICommand ConnectCommand
    {
        get
        {
            if (_connectCommand == null)
            {
                _connectCommand = new RelayCommand(param => ConnectCommandExecute(),
                                                   param => ConnectCommandCanExecute);
            }
            return _connectCommand;
        }
    }
    
    private bool ConnectCommandCanExecute
    {
        get { return !_instrumentModel.IsConnected; }
    }
    
    private void ConnectCommandExecute()
    {
        if (TcpSettingsChanged()) SaveTcpSettings();
        _instrumentModel.Connect(_tcpData);
    }
    

    中继类

    使这个简单的一部分是我在我的一个核心库 .dll 中拥有的 RelayClass。我可能从我看过的一个视频中得到了这个。这可以完整地剪切和粘贴,这里不需要自定义任何内容,除非您可能想要更改它所在的命名空间。
    using System;
    using System.Diagnostics;
    using System.Windows.Input;
    
    namespace Syncor.MvvmLib
    {
    public class RelayCommand : ICommand
    {
    private readonly Action<object> _execute;
    private readonly Predicate<object> _canExecute;
    
    public event EventHandler CanExecuteChanged
    {
      add
      {
        CommandManager.RequerySuggested += value;
      }
      remove
      {
        CommandManager.RequerySuggested -= value;
      }
    }
    
    public RelayCommand(Action<object> execute)
      : this(execute, (Predicate<object>) null)
    {
      this._execute = execute;
    }
    
    public RelayCommand(Action<object> execute, Predicate<object> canExecute)
    {
      if (execute == null)
        throw new ArgumentNullException("execute");
      this._execute = execute;
      this._canExecute = canExecute;
    }
    
    [DebuggerStepThrough]
    public bool CanExecute(object parameter)
    {
      if (this._canExecute != null)
        return this._canExecute(parameter);
      else
        return true;
    }
    
    public void Execute(object parameter)
    {
      this._execute(parameter);
    }
    }
    }
    

    关于wpf - 双击 WPF ListView - 如何触发命令而不使用事件处理程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10457554/

    相关文章:

    wpf - PRISM/Unity IDisposable

    .net - 带有 Caliburn.Micro 的复杂 WPF 组合框

    c# - ItemsControl 数据绑定(bind)不起作用?

    c# - 使用 xaml 在数据网格中选择行后更改 DataGridTemplateColumn 中的复选框状态

    wpf - 添加选项卡时,TabControl 的 SelectedItem 被 NewItemPlaceholder 覆盖

    mvvm - MVVM Light Toolkit与Cinchv2?

    c# - 将新项目添加到 CSLA EF4 模式

    c# - WPF 自定义复合用户控件

    c# - 如何解析 MarkupExtension 中数据绑定(bind)的值?

    c# - 如何在 C# 中使用我的软件设置在客户端系统上安装 MySQL 服务器?