2012-04-12 4 views
48

Così ho cercato in giro e non riesco a scoprire esattamente come fare questo. Sto creando un controllo utente usando MVVM e vorrei eseguire un comando sull'evento 'Loaded'. Mi rendo conto che questo richiede un po 'di codice, ma non riesco a capire cosa è necessario. Il comando si trova nel ViewModel, che è impostato come il datacontext della vista, ma non so esattamente come instradarlo, così posso chiamarlo dal codice retrostante dell'evento caricato. Fondamentalmente quello che voglio è qualcosa di simile ...Comando di chiamata dal codice dietro

private void UserControl_Loaded(object sender, RoutedEventArgs e) 
{ 
    //Call command from viewmodel 
} 

Guardandosi intorno non riesco a trovare la sintassi per questo ovunque. Devo prima legare il comando in xaml per poterlo fare riferimento? Ho notato l'opzione binding comando all'interno di un controllo utente non vi permetterà di associare i comandi che puoi entro qualcosa di simile a un pulsante ...

<UserControl.CommandBindings> 
    <CommandBinding Command="{Binding MyCommand}" /> <!-- Throws compile error --> 
</UserControl.CommandBindings> 

Sono sicuro che c'è un modo semplice per fare questo, ma posso' t per la vita di me capirlo.

risposta

101

Beh, se il DataContext è già impostata in cui potresti giocare e chiamare il comando:

var viewModel = (MyViewModel)DataContext; 
if (viewModel.MyCommand.CanExecute(null)) 
    viewModel.MyCommand.Execute(null); 

(Modifica parametro in base alle esigenze)

+0

Sì, è esattamente quello di cui avevo bisogno, sapevo che c'era un modo semplice. Grazie! –

+0

@KDiTraglia: Prego, lieto che abbia aiutato. –

+0

Dovresti controllare se viewModel è nullo prima di provare ad accedere a MyCommand. So che la mia soluzione no, ma la tua è la risposta accettata, quindi dovrebbe probabilmente essere lì dentro. – Alain

1

Prova questo:

private void UserControl_Loaded(object sender, RoutedEventArgs e) 
{ 
    //Optional - first test if the DataContext is not a MyViewModel 
    if(!this.DataContext is MyViewModel) return; 
    //Optional - check the CanExecute 
    if(!((MyViewModel) this.DataContext).MyCommand.CanExecute(null)) return; 
    //Execute the command 
    ((MyViewModel) this.DataContext).MyCommand.Execute(null) 
} 
+2

Non si dovrebbe chiamare un comando senza assicurarsi che possa essere eseguito per primo. –

+0

Se si sta utilizzando CanExecute solo per determinare se l'utente può eseguirlo (cioè legare allo stato abilitato di un pulsante) non c'è niente di sbagliato in esso. – Alain

+3

Con un pulsante il controllo garantisce che il comando non venga mai eseguito con noncuranza, se lo esegui manualmente devi prenderne cura tu stesso. –

3

Prefazione: senza saperne di più sui tuoi requisiti, sembra che un codice puzzolente esegua un comando da code-behind al momento del caricamento. Ci deve essere un modo migliore, MVVM-saggio.

Ma, se si ha realmente bisogno di farlo in codice dietro, qualcosa di simile sarebbe probabilmente il lavoro (nota: non riesco a provare questo al momento):

private void UserControl_Loaded(object sender, RoutedEventArgs e)  
{ 
    // Get the viewmodel from the DataContext 
    MyViewModel vm = this.DataContext as MyViewModel; 

    //Call command from viewmodel  
    if ((vm != null) && (vm.MyCommand.CanExecute(null))) 
     vm.MyCommand.Execute(null); 
} 

Anche in questo caso - cercare di trovare un modo migliore ...

+1

Dopo aver cercato sull'argomento, non c'è davvero un modo semplice, e il consenso generale che ho visto è un piccolo codice che non ha mai ucciso nessuno. –

+1

@KDiTraglia - vero, ma in generale, il "piccolo codice dietro" in genere si riferisce ad azioni che hanno effetto solo sulla Vista stessa (ad esempio cose come selezionare tutto il testo in una casella di testo quando si concentra). Qui, stai interagendo direttamente con ViewModel dal code-behind di View, che infrange il principio MVVM. –

1

Ho una soluzione più compatta che voglio condividere. Dato che eseguo spesso comandi nei miei ViewModels, mi sono stancato di scrivere la stessa istruzione. Così ho scritto un'estensione per l'interfaccia ICommand.

using System.Windows.Input; 

namespace SharedViewModels.Helpers 
{ 
    public static class ICommandHelper 
    { 
     public static bool CheckBeginExecute(this ICommand command) 
     { 
      return CheckBeginExecuteCommand(command); 
     } 

     public static bool CheckBeginExecuteCommand(ICommand command) 
     { 
      var canExecute = false; 
      lock (command) 
      { 
       canExecute = command.CanExecute(null); 
       if (canExecute) 
       { 
        command.Execute(null); 
       } 
      } 

      return canExecute; 
     } 
    } 
} 

e questo è come si dovrebbe eseguire il comando in codice:

((MyViewModel)DataContext).MyCommand.CheckBeginExecute(); 

Spero che questo accelererà il vostro sviluppo solo un po 'più piccolo. :)

P.S. Non dimenticare di includere anche lo spazio dei nomi di ICommandHelper. (Nel mio caso è SharedViewModels.Helpers)