我对如何在我的特定情况下将事件实现为命令感到有些困惑。我想尊重MVVM,但在这种情况下不知道如何。
我有一个WPF'视图' - viewCustomerSearch。它上面有一些文本框,当用户点击“搜索”时,结果将填充在ListView中。 viewCustomerSearch绑定到viewmodelCustomerSearch,它运行良好。
viewCustomerSearch托管在viewCustomer上。
我想知道viewCustomerSearch公开一个自定义命令 - CustomerSelectedCommand - 只要双击viesCustomerSearch中的ListView,然后由viewCustomer(viewmodelCustomer)后面的viewmodel处理,就会'触发'。这似乎是正确实现的理论MVVM模式。
我已将主要问题分解为三个较小的问题,但希望您可以看到它们都是同一挑战的组成部分。
第一个问题:为了让viewCustomerSearch公开自定义命令,我似乎必须将此代码放在viewCustomerSearch中 - 这似乎“打破”了MVVM(后面的视图代码中没有代码)。
public readonly DependencyProperty CustomerSelectedCommandProperty = DependencyProperty.Register("CustomerSelectedCommand", typeof(ICommand), typeof(viewCustomerSearch));
public ICommand CustomerSelectedCommand
{
get { return (ICommand)GetValue(CustomerSelectedCommandProperty); }
set { SetValue(CustomerSelectedCommandProperty, value); }
}
第二个问题(这是我真正想要的那个):最好通过展示我会做什么打破MVVM来解释。我在视图中有一个事件处理程序:
private void lstResults_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
if (CustomerSelectedCommand != null) CustomerSelectedCommand.Execute(((ViewModels.viewmodelCustomerSearchResult)this.lstResults.SelectedItem).CustomerId);
}
嗯......我知道你不应该把这个事件处理程序放在这里;相反,它应该有一个Command来在viewmodelCustomerSearch中处理它。这里的两个问题是
因为'CustomerSelectedCommand'ICommand是在中实现的 viewCustomerSearch,viewmodelCustomerSearch无法看到它来触发它。
我看不到如何将MouseDoubleClick事件绑定到命令,而不是后面的视图代码中的事件处理程序。我正在阅读有关附加属性的内容,但无法看到它们如何应用于此处。
(请注意:我在应用程序的其他地方使用常见的'RelayCommand';这会在这里发挥作用吗?)
第三个问题:当我使用非MVVM方式在事件处理程序后面的代码中触发命令时,您可以看到我将所选客户ID作为争论传入命令。如何在viewCustomer的Command处理程序中看到该参数?我创建了一个新的RelayCommand来处理它,但似乎Execute方法不接受参数?
考虑到上述所有情况,我不得不说我个人并不赞成'MVVM意味着在视图中没有代码'。这对我来说似乎很疯狂;与视图完全相关的代码,仅视图,不应该 - 恕我直言 - 进入视图模型。尽管如此,这看起来似乎是逻辑上的东西(不是查看内容)。
非常感谢您的一些见解。对不起,很长的帖子;试图平衡足够的信息,帮助我“战争与和平”。
DS
答案 0 :(得分:0)
在您的视图中,您可以在xaml中添加“Command”属性并将其绑定到ViewModel的命令
Command="{Binding CustomerSelectedCommand}"
参数可以多种方式传递。大多数时候,我只有其他项目绑定到我的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很有帮助。
我只是要抓取一些正常工作的代码,这里是如何将一个Command属性添加到XAML中的按钮。
<Button Command="{Binding ConnectCommand}">
//Your button content and closing </Button> here
这假设您已将DataContext设置为具有名为ConnectCommand的Command的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);
}
}
}
答案 1 :(得分:0)
为什么不将它命名为“DoubleClickCommand”,这样您就不会将业务逻辑置于控制之中。然后将此命令绑定到您的viewmodel,就像Tod解释的那样。 关于你的代码背后,有一个纯xaml解决方案,更准确地说它涉及附加行为,但不需要覆盖WPF类(我想避免),搜索“事件上的fire命令”,例如{{ 3}}。 最后一件事:Code Behind不会以任何方式打破MVVM,我想知道这个神话来自哪里。代码背后完全没问题! MVVM是分离视图和逻辑,而不是告诉你在哪里放置你的代码。设计原则应该有所帮助,而不是阻碍你。