2013-01-12 19 views
26

Nella demo, ho un pulsante per attivare o disattivare un campo bool isAsking. Creo un comando che può essere eseguito solo quando isAsking==true.Quando viene chiamato CanExecute?

Dopo aver premuto il pulsante di commutazione, le modifiche immediatamente indicano che il comando trova la modifica di isAsking.

Mi sento molto confuso perché l'oggetto comando rileva la modifica di un campo, quando verrà chiamato CanExecute?

Anche se si scrive un'applicazione WPF per qualche tempo, sono nuovo al comando WPF. Si prega di fornire una spiegazione a questo caso e, se possibile, indicare alcuni articoli o blog correlati (ho già letto troppi articoli che parlano del comando taglia/incolla).

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     x:Class="WpfApplication1.MainWindow" 
     Title="MainWindow" Height="350" Width="525" x:Name="mainWindow" > 
    <StackPanel> 
     <Button Name="okButton" Content="Ok" /> 
     <Button Content="Toggle" Click="Button_Click_1"/> 
    </StackPanel> 
</Window> 

Codice-behind:

public partial class MainWindow : Window 
{ 
    private bool isAsking; 

    public MainWindow() 
    { 
     InitializeComponent(); 

     CommandBinding cb = new CommandBinding(); 
     cb.Command = okCommand; 
     cb.CanExecute += CanOKExecute; 
     cb.Executed += cb_Executed; 
     mainWindow.CommandBindings.Add(cb); 
     okButton.Command = okCommand; 
    } 

    private RoutedCommand okCommand = new RoutedCommand("ok", typeof(MainWindow)); 


    void cb_Executed(object sender, ExecutedRoutedEventArgs e) 
    { 

    } 

    void CanOKExecute(object sender, CanExecuteRoutedEventArgs e) 
    { 
     e.CanExecute = isAsking; 
    } 

    private void Button_Click_1(object sender, RoutedEventArgs e) 
    { 
     isAsking = !isAsking; 
    } 
} 

risposta

23

provo a cercare "il CommandManager rileva le condizioni" e raggiungere this exellent article.

Esaminando NET codice sorgente Framework, l'autore ritiene che la CommandManager non rileva le condizioni di per sé, piuttosto che quando Keyboard.KeyUpEvent, Mouse.MouseUpEvent, Keyboard.GotKeyboardFocusEvent o Keyboard.LostKeyboardFocusEvent verifica, sarà rivalutare metodo CanExecute.

L'articolo include altre informazioni, ma la parte precedente è stata sufficiente per me.

+6

I Sono un po 'inorridito da questo comportamento predefinito. Se un modulo ha molti controlli e i metodi CanExecute sono scritti in modo subottimale, questa è una quantità orribilmente grande di valutazioni CanExecute potenzialmente inutili no? Hai difficoltà a vedere come scala l'architettura? – Shiv

27

La risposta tecnica è che CanExecute verrà richiamato ogni volta viene generato l'evento CommandManager.RequerySuggested. Secondo la documentazione, questo sarà ...

... quando il CommandManager rileva condizioni che potrebbero modificare la capacità di un comando da eseguire.

In termini pratici, ciò significa solo che non c'è bisogno di preoccuparsi quando CanExecute si chiama: WPF invocherà quando si pensa che sia opportuno, e nella mia esperienza questo sarà quasi sempre coprire le vostre esigenze.

L'eccezione a questo è se si dispone di un'attività in background che causerà CanExecute per modificare il valore restituito in base a qualcosa che non viene attivato dall'interfaccia utente. In questo scenario, potrebbe essere necessario forzare manualmente il runtime di WPF di ri-query CanExecute che si può fare chiamando CommandManager.InvalidateRequerySuggested

+6

oppure, se si tratta di un Prisma 'DelegateCommand' - chiama' RaiseCanExecuteChanged() 'sul' Command' stesso. – Default

+4

@Default true. Allo stesso modo, se si tratta della propria implementazione 'ICommand', è possibile aumentare manualmente l'evento' CanExecuteChanged' sul comando –

+0

Doyyy .. Mi sono completamente dimenticato di quell'evento in 'ICommand'. Qui ho pensato che Prism era su qualcosa :) – Default

8

RoutedCommand contiene un evento CanExecuteChanged cui agganciare internamente alla manifestazione CommandManager.RequerySuggested -

public event EventHandler CanExecuteChanged 
    { 
     add { CommandManager.RequerySuggested += value; } 
     remove { CommandManager.RequerySuggested -= value; } 
    } 

E CommandManager.RequerySuggested evento viene generato

ogniqualvolta modifiche all'origine comando vengono rilevati dal comando gestore che è nel tuo caso è Window. Quindi, quando si fa clic sul pulsante, commandManager genera l'evento RequerySuggested e quindi esegue il predicato CanExecute registrato per il comando.

Inoltre, CommandManager ha un metodo statico - InvalidateRequerySuggested che costringe il CommandManager per sollevare il RequerySuggestedEvent. Quindi, puoi chiamarlo per convalidare i tuoi comandi troppo manualmente.

Problemi correlati