【问题标题】:WPF Commands - Relation of View to the ModelWPF 命令 - 视图与模型的关系
【发布时间】:2014-05-01 02:20:16
【问题描述】:

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

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

问题是,据我了解,视图甚至不认为知道模型。那么如何让 View 中的按钮执行我想要的操作呢?

【问题讨论】:

    标签: c# wpf mvvm


    【解决方案1】:

    你需要使用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}" />
    

    【讨论】:

      【解决方案2】:

      这就是视图模型的用武之地。首先,您应该考虑使用命令而不是事件处理程序。使用命令,您可以将“动作”绑定到按钮,而不是将事件硬编码到 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。

      【讨论】:

      • 我知道数据上下文,但从未听说过 ViewModelLocator 而不是依赖注入...在您的代码中,ExecuteAction 方法用于什么?你是用它来定义命令吗?
      • ExecuteAction 是您调用模型操作的位置。这样 ViewModel 就可以从 View 中隐藏 Model。网上有很多关于 VievModelLocators 和 Dependency Injection 的信息。例如,下载 MVVM Light Toolkit,您可以将所有这些东西放在一个不错的工具包中,并提供源代码供您阅读。
      【解决方案3】:

      在你的模型中你有你的功能:

      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,例如:

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-08-06
        • 1970-01-01
        • 2010-11-28
        • 1970-01-01
        • 1970-01-01
        • 2015-05-18
        相关资源
        最近更新 更多