Comandos MVVM - um comando para tudo ou vários comandos?

5

Na minha última empresa, ao manipular comandos de visualização, no ViewModelBase havia um comando central implementado, como

public ICommand ToolCommand { get; set; }

E no ViewModelBase, ele foi inicializado e todos os botões conectados a este comando foram diferenciados por seu parâmetro de comando:

public ViewModelBase()
{
    ToolCommand = new RelayCommand<String>(Execute, CanExecute);
}

Na base do modelo de exibição, as funções Execute e CanExecute eram virtuais (implementando comandos genéricos como Close e assim por diante) e nas classes derivadas, a função Execute e CanExecute era um grande switch, estendendo a funcionalidade básica, mais ou menos assim:

public void Execute(String parameter)
{
    switch (parameter)
    {
        case "Refresh":
          RefreshGrid();
          break;
        case "OtherStuff":
          Other();
          break;
        default:
          base.Execute(parameter);
    }
}

Nestes casos, quando acabamos de adicionar um botão, adicionamos outro caso de comutador nos modelos de exibição adequados.

No entanto, na minha empresa atual, a regra é que cada botão tem uma propriedade de comando específica, como

public ICommand RefreshCommand { get; set; }
public ICommand OtherStuffCommand { get; set; }

e iniciado um por um:

RefreshCommand = new RelayCommand<String>(RefreshGrid(), _canRefresh);
OtherStuffCommand = new RelayCommand<String>(OtherStuff(), _canDoOther);

No escritório, não podemos concordar com o que é melhor em termos de compactação, beleza e depurabilidade. Certamente não vamos reescrever as partes de trabalho por causa de seu custo, mas considerando novos projetos, achamos difícil discutir quais têm mais vantagens.

Qual e por que dessas duas abordagens é melhor?

    
por ermahgerd 29.06.2016 / 13:36
fonte

3 respostas

5

Acho que usar a instrução switch com strings é uma ideia terrível pelos seguintes motivos:

  1. Seus comandos não podem receber um parâmetro real porque você usou o CommandParameter para identificar o comando em si.
  2. Seus métodos Execute e CanExecute se tornam grandes blobs, onde é impossível dizer se você está realmente manipulando todos os seus comandos, já que é necessário fazer referência cruzada ao ViewModel com cada arquivo XAML vinculado a ele.
  3. Alguns comandos não precisam de um CanExecute. Se você tiver cada comando como uma propriedade individual, é muito fácil dizer quais comandos suportam CanExecute e quais não. Com as declarações switch, é muito mais difícil determinar isso.
  4. É muito difícil substituir o comportamento de um único comando em uma classe derivada. Se você tiver uma classe ViewModel filha, a única maneira de substituir o comportamento de um comando é copiar todo o método Execute (String parameter) e alterar a declaração de um caso em que você está interessado.
  5. Ferramentas de análise estática não podem dizer a você que sua ligação de comando no XAML está errada porque seu CommandParameter é apenas uma cadeia arbitrária.

Eu acho que as desvantagens da instrução switch com a abordagem de string são tão strongs que eu encorajaria a refatoração de projetos existentes para não fazerem dessa maneira.

    
por 29.06.2016 / 16:08
fonte
1

Acho que a principal coisa a considerar aqui é a ausência do ViewModel.

Ou seja. Na sua opinião, você terá ligações para os vários botões, etc, e você precisa diferenciá-los.

Suas escolhas serão feitas

NamedCommand(parameter)
GenericCommand(name, parameters)

Eu acho bastante óbvio que um parâmetro se torna um nome de comando em vez de um parâmetro para o mesmo comando e nesses casos eu acho que você deve preferir o NamedCommand.

Embora eu possa ver que pode haver casos extremos em que a nomenclatura é difícil

    
por 29.06.2016 / 13:49
fonte
1

A ideia por trás de um comando é que não é específico para uma visão. Você pode querer executar o mesmo comando a partir de um botão em sua visão, ou uma opção de menu, ou a partir de um menu de contexto do botão direito, ou de uma miríade de outros elementos da interface do usuário. Criando classes de comando específicas, você ganha Responsabilidade Única e reutilização. Eu não recomendaria que seu modelo de visão definisse o comportamento de seus comandos. Você acabará copiando / colando o código em toda a sua base de código.

    
por 29.06.2016 / 15:34
fonte

Tags