WPF命令 - 视图与模型的关系

时间:2014-03-23 21:30:38

标签: c# wpf mvvm

我试图更好地了解WPF开发的MVVM设计模式,这是本主题的一个基本问题。

让我们说我已经实现了模型,并且它有一个执行主要操作的方法。在视图中我想创建一个按钮,按下该按钮将激活此操作。为了做到这一点,我需要将Click事件与事件处理程序相关联,实际上只是调用模型方法。

问题在于,据我所知,该观点甚至不想知道模型。那么如何让View中的按钮执行我想要的操作呢?

3 个答案:

答案 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 - 接口

时获得的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);

然后你必须在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}" />