简体   繁体   中英

Handling lots of commands in WPF MVVM

I'm looking for advice on handle a growing number of commands in a wpf mvvm project.

My viewmodels are collecting a good number of them, and I feel like before the project is matured I need to do something better to handle them. Right now all my commands are just listed as properties in my viewmodels, and either loaded in the constructor of the VM, or lazy loaded.

And if it matters I'm using MVVM Light's RelayCommand implementation of ICommand.

I've seen on a larger open source project putting them in collections, and grouping those collections into more collections...that all seemed really messy to me, but the context was a little different, as all those commands were binding to menus. I don't have a typical drop down menu in this application, but I do use many different context menus/buttons.

Anyways, what are some ideas on handling commands, from both a code readability/maintainability as well as functional perspective?

This post show you how to create dynamic properties for exposing your custom commands. You can mix this with reflection in order to handle a lot of commands.

Create a custom attribute:

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

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

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

Then mark all your command with it:

[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;
}

You can then load all commands at application startup:

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));
        }
    }
}

This architecture can be easily extended to support defining commands in plugins.

Meh... if it bothers you to look at them, then put them in a #region and collapse the region. The guy who suggested putting them in a dictionary, so you only have one property that seems like a maintenance headache to me... and the XAML binding gets messy.

Right now all my commands are just listed as properties in my viewmodels, and either loaded in the constructor of the VM, or lazy loaded.

Instead of making a distinct property for each command in the ViewModel , try making a single collection property Commands to hold all commands in the ViewModel .

This way you simply create and add all the commands to the Commands collection in the ViewModel constructor or even from a factory method outside the ViewModel constructor.

Anyways, what are some ideas on handling commands, from both a code readability/maintainability as well as functional perspective?

  1. 95% of cases there is no need to differentiate between commands in the ViewModel .

  2. It's easier to maintain one collection property that to maintain lots of properties in the ViewModel .

  3. Commands collection can be easily made composite and mapped to a toolbar or a hierarchical context menu.

  4. The ability to add commands to ViewModel without changing the existing class or subclassing is really great.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM