如何处理MVVM中动态按钮中的执行条件和可以执行条件

时间:2018-12-03 21:22:51

标签: c# wpf mvvm

我的TabControl中有一个Button作为附件,其中有5个TabItem。此按钮复制选项卡中使用的不同对象。每个TabItem都有一个CustomView(所有组件都驻留在其中,TextView,TextBox等),我希望能够在一个命令中为每个选项卡实现与该Button不同的功能,因此我实现了一个通用的Copy Command,该命令用于检查当前选项卡索引以查看我们当前处于哪个选项卡中,但是现在,如果不在Conditions方法中重复执行切换用例,处理无法执行条件的最佳方法是什么?例如,如果第一个选项卡按钮的 object 为空,则无法执行(禁用),而第二个选项卡按钮的对象为null。

  • 第一个标签“用户”具有CustomerView

  • 第二个标签“活动”具有一个ActivityView

代码:

public RelayCommandWithCannotExecuteReason Copy
        {
            get
            {
                if (_copy == null)
                {
                    _copy = new RelayCommandWithCannotExecuteReason(
                        x =>
                        {

                            switch (SelectedTabIndex) {
                                case 1:
                                    Clipboard.SetData("First", object1);
                                    break;
                                case 2:

                                    Clipboard.SetData("Second", object2;
                                    break;
                            }

                        }, CanCopyConditions);
                }

                return _copy;
            }
        }

1 个答案:

答案 0 :(得分:1)

为什么不继承类型RelayCommandWithCannotExecuteReason并创建专用命令对象?所有逻辑都包含在命令中,您要做的就是在所有视图模型中实例化多个命令。

创建专用命令类来处理VM特定逻辑没有错,程序员正是这样做的。创建像ICommand或您的RelayCommandWithCannotExecuteReason这样的抽象的特定实现是SOLID。

public class CopyCommand : RelayCommandWithCannotExecuteReason
{
    ViewModel _vm;
    public CopyCommand( ViewModel vm)
    { 
       _vm = vm;
    }

    public void Execute(object parameter) 
    {
       switch (_vm.SelectedTabIndex) 
       {
         case 1:
            _vm.Clipboard.SetData("First", object1);
            break;
         case 2:
           _vm.Clipboard.SetData("Second", object2;
            break;
        }
    }

    public bool CanExecute(object parameter)
    {
        return true;
    }

}

现在,您在VM中使用此命令。有很多简单的方法,下面是一个示例,类似于您现在的方法...

 public CopyCommand Copy
 {
     get
     {
          if (_copy == null)
          {
             _copy = new CopyCommand(this);
          }
       return _copy;
      }

或在主VM的构造器或初始化器中创建实例:

public ViewModel() //constructor
{
  _copy = new CopyCommand(this);

}

public CopyCommand Copy
{
     get
     {
         return _copy;
     }
}

如果每个选项卡都有一个视图模型实例,并且想要将CanExecute()逻辑委托给“ SelectedTab”,那么您将需要这样的东西:

假设您的所有视图模型都继承了这样的基类:

public abstract class BaseTabViewModel
{
   public abstract bool CanCopy();
}

然后,您将在选项卡视图模型中将此基类作为子类。您将实现抽象:

 public class Tab1ViewModel : BaseTabViewModel
 {
    …

 public override bool CanCopy(){
     //custom logic....
     return true; 
 }

现在,我们需要更改CopyCommand的顺序以引用抽象,我最初将该命令编码为使用ViewModel,现在我们将类型定义为抽象。因此,更改ViewModel类:

public class CopyCommand : RelayCommandWithCannotExecuteReason
{
    BaseTabViewModel _vm;
    public CopyCommand( BaseTabViewModel vm)
    { 
      _vm = vm;
    }

现在CanExecute()方法可以调用适当的逻辑:

 public bool CanExecute(object parameter)
 {
      return _vm.CanCopy();
 }

这仅在以下情况下有效:

  • 所有选项卡视图模型都是BaseTabViewModel类型的实例。

此机制更加面向对象,并且更加灵活。祝你好运。