MVVM Commands - un comando per tutto o più comandi?

5

Nella mia ultima azienda, nella gestione dei comandi di visualizzazione, in ViewModelBase esisteva un comando centrale implementato, come

public ICommand ToolCommand { get; set; }

E nel ViewModelBase, è stato inizializzato e tutti i pulsanti collegati a questo comando sono stati differenziati dal suo parametro di comando:

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

Nel modello di visualizzazione delle basi, le funzioni Execute e CanExecute erano virtuali (implementando comandi generici come Close e così via) e nelle classi derivate, la funzione Execute e CanExecute era un grande interruttore, estendendo la funzionalità di base, sembrava più o meno così:

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

In questi casi, quando abbiamo aggiunto un pulsante, abbiamo aggiunto un altro caso di switch nei modelli di visualizzazione appropriati.

Tuttavia, nella mia attuale azienda, la regola è che ogni pulsante ha una specifica proprietà del comando, come

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

, e avviato uno per uno:

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

In ufficio non possiamo concordare quale sia il migliore in termini di compattezza, bellezza, debugabilità. Sicuramente non riscriveremo le parti di lavoro a causa dei suoi costi, ma considerando nuovi progetti che troviamo difficili da discutere e che ha più vantaggi.

Quale e perché di questi due approcci è meglio?

    
posta ermahgerd 29.06.2016 - 13:36
fonte

3 risposte

5

Penso che l'uso dell'istruzione switch con le stringhe sia una pessima idea per i seguenti motivi:

  1. I tuoi comandi non possono prendere un parametro effettivo perché hai usato il CommandParameter per identificare il comando stesso.
  2. I metodi Execute e CanExecute diventano blob di grandi dimensioni in cui è impossibile stabilire se si stanno effettivamente gestendo tutti i comandi poiché è necessario eseguire il riferimento incrociato a ViewModel con ogni singolo file XAML ad esso associato.
  3. Alcuni comandi non hanno bisogno di un CanExecute. Se si dispone di ciascun comando come proprietà individuale, è molto semplice stabilire quali comandi supportano CanExecute e quali no. Con le istruzioni switch, è molto più difficile determinarlo.
  4. È molto difficile sovrascrivere il comportamento per un singolo comando in una classe derivata. Se hai una classe ViewModel secondaria, l'unico modo per sovrascrivere il comportamento per un comando è copiare l'intero metodo Execute (Parametro stringa) e modificare l'unica dichiarazione a cui sei interessato.
  5. Gli strumenti di analisi statica non possono dirti che il tuo comando vincolante in XAML è sbagliato perché il tuo CommandParameter è solo una stringa arbitraria.

Penso che gli aspetti negativi dell'istruzione switch con approccio a stringa siano così forti da incoraggiare il refactoring di progetti esistenti per non farlo in questo modo.

    
risposta data 29.06.2016 - 16:08
fonte
1

Penso che la cosa fondamentale da considerare qui è la vista in assenza di ViewModel.

Ie. Nella tua vista avrai collegamenti per i vari pulsanti ecc. E dovrai distinguerli.

Le tue scelte verranno scambiate

NamedCommand(parameter)
GenericCommand(name, parameters)

Penso che sia abbastanza ovvio dove un parametro diventa un nome di comando piuttosto che un parametro per lo stesso comando e in quei casi penso che dovresti preferire NamedCommand.

Anche se vedo che potrebbero esserci casi limite in cui la denominazione è difficile

    
risposta data 29.06.2016 - 13:49
fonte
1

L'idea alla base di un comando è che non è specifico per una vista. Potresti voler eseguire lo stesso comando da un pulsante sulla tua vista, o da un'opzione di menu, o da un menu di scelta rapida con il tasto destro del mouse, o da una miriade di altri elementi dell'interfaccia utente. Creando classi di comando specifiche, ottieni la responsabilità unica e la riusabilità. Non consiglierei che il tuo modello di vista definisca il comportamento dei loro comandi. Finirai per copiare / incollare il codice in tutta la tua base di codice.

    
risposta data 29.06.2016 - 15:34
fonte

Leggi altre domande sui tag