我对如何在我的特定情况下将事件实现为命令感到有些困惑。我想尊重 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 中处理它。这里的两个问题是
viewCustomerSearch,viewmodelCustomerSearch 看不到它来触发它。
(请注意:我在应用程序的其他地方使用通用的“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/