我试图更好地了解WPF开发的MVVM设计模式,这是本主题的一个基本问题。
让我们说我已经实现了模型,并且它有一个执行主要操作的方法。在视图中我想创建一个按钮,按下该按钮将激活此操作。为了做到这一点,我需要将Click
事件与事件处理程序相关联,实际上只是调用模型方法。
问题在于,据我所知,该观点甚至不想知道模型。那么如何让View中的按钮执行我想要的操作呢?
答案 0 :(得分:1)
这就是视图模型的用武之地。首先,您应该考虑使用命令而不是事件处理程序。使用命令,您可以将“操作”绑定到按钮,而不是将事件硬编码到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的Command属性。要设置视图视图模型,请使用View.Datacontext。这可以通过几种不同的方式完成。这里也可以使用依赖注入。另一种解决方案是使用ViewModelLocator,它使用Locator模式将视图连接到ViewModel。
答案 1 :(得分:1)
在你的模特中你有你的功能:
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
- 接口
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);
然后你必须在viewmodel中创建一个方法,你可以在其中调用模型的MyAction-Method:
public void MyCommandExecute(object parameter) { this.mainWindowModel.MyAction(); }
在你的xaml中,你必须设置DataContext,如:
<Window.DataContext>
<viewModel:MainWindowViewModel/>
</Window.DataContext>
小viewModel是ViewModel的命名空间。您必须在Window-Definition中添加如下内容:
xmlns:viewModel="clr-namespace:TestApplication.ViewModel"
现在您可以将button-Command绑定到ViewModel的ICommand-Property,如:
答案 2 :(得分:0)
您需要使用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}" />