【问题标题】:ICommand implementations in a separate classes, using only MVVM Light?ICommand 在单独的类中实现,仅使用 MVVM Light?
【发布时间】:2014-03-03 20:09:18
【问题描述】:

我们有一个带有丝带的大型应用程序。功能区按钮都绑定到我的主视图模型(主应用程序窗口的数据上下文)中的命令。

随着我们创建大量 RelayCommand(绑定到各种功能区命令),MainViewModel 的构造函数开始增长。它看起来像这样:

    public MainWindowViewModel()
    {
        this.OpenProjectCommand = new RelayCommand(() =>
            {
                 // buncha code
            });

        this.ProjectTypesCommand = new RelayCommand(() =>
            {
                // more code
            });

        this.NewSectionCommand = new RelayCommand(() =>
            {
                // code code code...
            });
        // ... only three ribbon buttons down, this is gonna get huge...
    }

我更希望有单独的类来实现每个命令,而不是 MainViewModel 的构造函数中的大量内联代码。 (或者在 MainViewModel 中创建大量委托,例如 OpenProject、CanOpenProject,然后将它们的引用传递给 RelayCommand 构造函数)。

我为什么不简单地在 CommandBase 中实现 ICommand,然后创建单独的命令?因为我想按照this question 成为“标准友好型”。

是否可以使用标准的 ICommand 实现,以便我的命令位于不同的类中?

我不想添加更多的 MVVM 框架,因为我已经在使用 MVVM Light。但我也不想重新发明轮子。

更新:MainViewModel.cs 不需要杂乱无章的#regions 或命令方法。恕我直言,扩展方法也不适合。

【问题讨论】:

  • 如何创建一个命令并在命令参数中指定一个条件,该条件将由该命令的执行方法中的 if 语句使用?
  • @devhedgehog 我希望将每个命令分成自己的类,但不会与既定的 MVVM 约定或 MVVM Light 的工具发生冲突(请参阅链接问题)。

标签: c# wpf mvvm mvvm-light command-pattern


【解决方案1】:

我的做法是拥有“子视图模型”。例如,在 MainViewModel 的情况下,假设您有一个PrintCommand 和一个CancelPrintCommand。您可以拥有一个名为PrinterViewModel 的新类,并在MainViewModel 中公开此类的一个实例。在这个PrinterViewModel 中有PrintCommand 和CancelPrintCommand(这也允许模块化单元测试,这很整洁)。

然后在 XAML 中:

Command="{Binding Main.Printer.PrintCommand}"

或者,你可以这样做

new RelayCommand(() => Printer.DoSomething())

这有意义吗?

干杯 洛朗

【讨论】:

    【解决方案2】:

    您至少可以在 getter 中创建它们。 你可以使用??操作员。

    http://msdn.microsoft.com/en-us/library/ms173224.aspx

    这基本上是说:返回_testCommand,但如果它仍然为空,则首先创建它。

    这样,在需要之前不会创建命令!

    public class TestViewModel : ViewModelBase
    {
        #region OpenCommand
        private RelayCommand _testCommand;
        public RelayCommand TestCommand {
            get {
                return _testCommand = _testCommand 
                    ?? new RelayCommand(
                        this.ExecuteOpenCommand, 
                        this.CanOpenCommandExecute);
            }
        }
        private void ExecuteOpenCommand()
        {
            // do stuff
        }
    
        private bool CanOpenCommandExecute()
        {
            return true;
        }
        #endregion
    }
    

    如果您的目标是组织,您可以使用#region 和#endregion。就像我们说的,如果您的目标是缩小构建过程,请使用 ?? getter 中的运算符。如果您只是讨厌内联代码,请在 getter 中结合 RelayCommand 创建私有方法。

    【讨论】:

    • 没错,这可能更干净一些;我真正想做的是在自己的类中实现每个命令,这样 MainViewModel.cs 就不会变得很大。我想知道是否有一种“公认的”方式来做到这一点。我正在使用的 MVVM 框架(MVVM Light)似乎不支持这一点,而无需滚动自己的 ICommand 实现。
    • 这对我来说听起来非常好。或者,为了避免编写新的 RelayCommand... 你不能在 MVVM Light 的 RelayCommand 的 base 构造函数中传递一个委托方法吗?
    • 我的意思是,写一个RelayCommand 的子类,称为OpenProjectCommand。并在 base 构造函数中传递 OpenProjectCommand 类的 method 作为参数。
    • 另一个提示。不要公开课程。只有特定的 ViewModel 类需要使用这些命令。所以......将它们保留在默认范围而不是公共范围内。
    • 我确实首先尝试过,子类化 RelayCommand 并将对其自己方法的引用传递给基本构造函数;这不起作用,因为“this”还不存在(如base(this.OpenProject, this.CanOpenProject))
    猜你喜欢
    • 2010-11-30
    • 1970-01-01
    • 2013-10-28
    • 2010-10-03
    • 2020-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多