处理大量命令在WPF MVVM中

4
我正在寻求关于如何处理wpf mvvm项目中日益增长的命令的建议。我的视图模型收集了许多命令,我感觉在项目成熟之前需要做些更好的处理方式。目前,所有的命令都只是列在视图模型的属性中,并在VM的构造函数中进行加载或者懒加载。
如果有影响的话,我正在使用MVVM Light的RelayCommand实现ICommand。
我曾在一个大型开源项目中看到把它们放在集合中,并将这些集合分组为更多的集合……但那似乎很混乱,因为所有这些命令都绑定到菜单。在这个应用程序中,我没有典型的下拉菜单,但我确实使用了许多不同的上下文菜单/按钮。
总之,从代码可读性/可维护性和功能的角度来看,有哪些处理命令的想法?

3
当我有很多命令时,我会将它们放在虚拟机的一个局部类中,该类名为XXXXCommanding,其中XXXX是虚拟机的名称。然而,我不赞成将它们放在集合中。如果我需要迭代所有命令,我会使用反射。 - Gayot Fow
4
你是否考虑过你的ViewModel可能正在做过多的工作? - CodeMonkey
1
我在这件事上支持@CodeMonkey的观点。滥用部分类将庞大的类分割成多个单独的文件只是掩盖问题。 - Daniel Mann
3
如果你发现自己需要制作很多类似“工具栏”的UI界面以及相应的命令(例如CRUD屏幕上的“新建”,“编辑”,“保存”,“取消”,“删除”等),可以考虑使用ObservableCollection<ICommand>并将UI实现为包含按钮的ItemsControl,其中ItemTemplate定义了按钮的样式。当有一些命令需要分组时,这是我通常采用的做法。 - Federico Berasategui
2
你能给我们提供这种ViewModel及其“众多”命令的示例吗(即哪些类型的命令)?我之所以问是因为我只有在看到超过3-4个命令的视图模型时才会认为它是反模式,也就是类似于“上帝对象”的东西。也许你的设计可以改进。 - k.m
显示剩余6条评论
3个回答

1

如果你看到这些代码感到不舒服,那么可以把它们放在一个 #region 中并折叠该区域。有人建议将它们放在一个字典中,这样只需要一个属性,但我认为这会带来维护上的麻烦...而且 XAML 绑定也会变得混乱。


1

这篇文章将向您展示如何创建动态属性以公开自定义命令。您可以将其与反射混合使用,以处理许多命令。

创建自定义属性:

[AttributeUsage(AttributeTargets.Class)]
public class CommandClassAttribute : Attribute
{
    readonly string commandName;

    public CommandClassAttribute(string commandName)
    {
        this.commandName = commandName;
    }

    public string CommandName
    {
        get { return commandName; }
    }
}

然后用它标记所有命令:
[CommandClass("New")]
public class NewCommand : ICommand
{
    public bool CanExecute(object parameter)
    {
        return true;
    }

    public void Execute(object parameter)
    {
        MessageBox.Show("New");
    }

    public event EventHandler CanExecuteChanged;
}

您可以在应用程序启动时加载所有命令:
readonly Dictionary<string, ICommand> commands = new Dictionary<string, ICommand>();

void LoadCommands()
{
    Type[] types = Assembly.GetExecutingAssembly().GetExportedTypes();
    var iCommandInterface = typeof(ICommand);
    foreach (Type type in types)
    {
        object[] attributes = type.GetCustomAttributes(typeof(CommandClassAttribute), false);
        if (attributes.Length == 0) continue;
        if (iCommandInterface.IsAssignableFrom(type))
        {
            string commandName = ((CommandClassAttribute)attributes[0]).CommandName;
            commands.Add(commandName, (ICommand)Activator.CreateInstance(type));
        }
    }
}

这种架构可以轻松扩展以支持在插件中定义命令。

0
现在我的所有命令都只是列在我的视图模型中的属性中,要么在VM的构造函数中加载,要么进行延迟加载。
与其为ViewModel中的每个命令创建一个不同的属性,不如尝试创建一个单一的集合属性Commands来保存ViewModel中的所有命令。
这样,您只需在ViewModel构造函数中或甚至从ViewModel构造函数外部的工厂方法中创建并添加所有命令到Commands集合中即可。
无论如何,有哪些处理命令的想法,无论是从代码可读性/可维护性还是功能角度考虑?
  1. 在95%的情况下,不需要区分ViewModel中的命令。

  2. 维护一个集合属性比维护ViewModel中的许多属性更容易。

  3. Commands集合可以轻松地组合并映射到工具栏或分层上下文菜单中。

  4. 能够在不更改现有类或子类的情况下向ViewModel添加命令真的很棒。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接