【发布时间】:2014-05-01 02:20:16
【问题描述】:
我试图更好地理解用于 WPF 开发的 MVVM 设计模式,这是本主题的一个基本问题。
假设我实现了模型,并且它有一个执行主要操作的方法。在视图中,我想创建一个按钮,按下它时将激活此操作。为此,我需要将Click 事件与事件处理程序相关联,这实际上只是假设调用模型方法。
问题是,据我了解,视图甚至不认为知道模型。那么如何让 View 中的按钮执行我想要的操作呢?
【问题讨论】:
我试图更好地理解用于 WPF 开发的 MVVM 设计模式,这是本主题的一个基本问题。
假设我实现了模型,并且它有一个执行主要操作的方法。在视图中,我想创建一个按钮,按下它时将激活此操作。为此,我需要将Click 事件与事件处理程序相关联,这实际上只是假设调用模型方法。
问题是,据我了解,视图甚至不认为知道模型。那么如何让 View 中的按钮执行我想要的操作呢?
【问题讨论】:
你需要使用ICommand接口,并提供一个实现,我建议你在MSDN上read this article。
在您的 ViewModel 中,您将创建一个 ICommand 的实例,例如ButtonClick,看起来像(基于 RelayCommand):
public class ViewModel
{
public ViewModel()
{
this.ButtonClick = new RelayCommand(_ => this.DoSomething());
}
public ICommand ButtonClick { get; set; }
public void DoSomething()
{
// Something...
}
}
然后在您的 xaml 中您将绑定到 ButtonClick:
<Button Text="Click" Command="{Binding ButtonClick}" />
【讨论】:
这就是视图模型的用武之地。首先,您应该考虑使用命令而不是事件处理程序。使用命令,您可以将“动作”绑定到按钮,而不是将事件硬编码到 Click 事件。像这样:
<Button Command="{Binding Path=ActionCommand}"/>
现在您的视图模型必须有一个实现 ICommand 的属性。对此有很多实现,例如 MVVM Light Toolkit 中的 RelayCommand。通过这个属性,你可以调用你的模型动作。这是通过对您的视图模型拥有的模型的引用来完成的。可以通过依赖注入设置对模型的引用,也可以在创建视图模型时提供它。
简单视图模型类:
public class ViewModel : INotifyPropertyChanged
{
private Model _model;
private ICommand _actionCommand;
public ViewModel(Model model)
{
_model = model;
_actionCommand = new RelayCommand(ExecuteAction);
}
public ICommand ActionCommand
{
get { return _actionCommand; }
}
private void ExecuteAction()
{
_model.Action();
}
}
这意味着您的视图并不真正知道 ViewModel 的类型,只是它有一个名为 ActionCommand 的命令属性。要设置 Views 视图模型,请使用 View.Datacontext。这可以通过几种不同的方式来完成。在这里也可以使用依赖注入。另一种解决方案是使用 ViewModelLocator,它使用 Locator 模式将视图连接到其 ViewModel。
【讨论】:
在你的模型中你有你的功能:
class MainWindowModel
{
public void MyAction()
{...}
}
在 ViewModel 的构造函数中,您可以创建模型的实例,例如:
class MainWindowViewModel
{
private readonly MainWindowModel mainWindowModel;
public MainWindowViewModel()
{
this.mainWindowModel = new MainWindowModel();
}
那么你就有了ICommand 的实现,比如 RelayCommand:
public class RelayCommand : ICommand
{
private readonly Action<object> execute;
private readonly Predicate<object> canExecute;
public RelayCommand(Action<object> exectue, Predicate<object> canExecute = null)
{
if (exectue == null)
throw new ArgumentNullException("exectue");
this.execute = exectue;
this.canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return this.canExecute == null || this.canExecute(parameter);
}
public void Execute(object parameter)
{
this.execute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
}
所以。现在您的 ViewModel 中有一个属性:
private ICommand myCommand;
public ICommand MyCommand
{
get { return this.myCommand; }
set
{
this.myCommand = value;
OnPropertyChanged();
}
}
实现INotifyPropertyChanged-Interface 时获得的 OnPropertyChanged-Event
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
在 ViewModel 的构造函数中,您可以像这样实例化 MyCommand
this.MyCommand = new RelayCommand(MyCommandExecute);
然后你必须在你的视图模型中创建一个方法来调用你的模型的 MyAction-Method:
public void MyCommandExecute(对象参数) { this.mainWindowModel.MyAction(); }
在您的 xaml 中,您必须像这样设置 DataContext:
<Window.DataContext>
<viewModel:MainWindowViewModel/>
</Window.DataContext>
小视图模型是您的视图模型的命名空间。您必须在 Window-Definition 中添加此内容,例如:
xmlns:viewModel="clr-namespace:TestApplication.ViewModel"
现在您可以将按钮命令绑定到 ViewModel 的 ICommand-Property,例如:
【讨论】: