2009-08-27 18 views
111

Mam Menu gdzie każdy MenuItem w hierarchii ma swoje Command własność ustawiony na RoutedCommand Mam zdefiniowane. Związane z nim CommandBinding zapewnia wywołanie zwrotne do oceny CanExecute, które steruje stanem aktywnym każdego z komputerów MenuItem.WPF - Jak zmusić polecenie do ponownej oceny „CanExecute” poprzez jej CommandBindings

Ten prawie działa. Pozycje menu początkowo pochodzą z poprawnymi stanami włączonymi i wyłączonymi. Jednak gdy dane, które mój callback CanExecute używają zmiany, potrzebuję polecenia, aby ponownie zażądać wyniku z mojego wywołania zwrotnego, aby ten nowy stan był odzwierciedlony w interfejsie użytkownika.

Dla tego nie są dostępne żadne publiczne metody dla RoutedCommand lub CommandBinding.

Należy pamiętać, że oddzwanianie jest ponownie używane po kliknięciu lub wpisaniu w formancie (domyślam się, że jest ono wyzwalane na wejściu, ponieważ przesunięcie kursorem myszy nie powoduje odświeżenia).

Odpowiedz

149

Nie najładniejszy w książce, ale można użyć CommandManager do unieważnienia wszystkich commandbinding:

CommandManager.InvalidateRequerySuggested(); 

Zobacz więcej informacji na temat MSDN

+0

Dzięki temu działało dobrze. W interfejsie użytkownika jest niewielkie opóźnienie, ale nie martwię się o to.Ponadto, natychmiast przegłosowałem twoją odpowiedź, a następnie oddałem głos, aby sprawdzić, czy zadziałało. Teraz, gdy to działa, nie mogę ponownie zastosować głosowania ponownie. Nie wiem, dlaczego SO ma tę regułę. –

+4

Edytowałem twoją odpowiedź, aby ponownie zastosować mój głos. Nie zmieniłem niczego w edycji. Dzięki jeszcze raz. –

+0

haha ​​ok :) dzięki! – Arcturus

72

dla każdego, kto jest po drugiej stronie to później; Jeśli używasz MVVM i Prism, wówczas implementacja ICommand pryzma zapewnia metodę .RaiseCanExecuteChanged(), aby to zrobić.

+10

Ten wzór znajduje się również w innych bibliotekach MVVM, na przykład MVVM Light. –

+1

W przeciwieństwie do Prism, kod źródłowy MVVM Light v5 wskazuje na jego 'RaiseCanExecuteChanged()' po prostu wywołuje 'CommandManager.InvalidateRequerySuggested()'. – Peter

+3

notatkę boczną do MVVM Light w WPF, należy użyć przestrzeni nazw GalaSoft.MvvmLight.CommandWpf, ponieważ GalaSoft.MvvmLight.Command będzie powodować problemy http://www.mvvmlight.net/installing/changes#v5_0_2 – fuchs777

21

Nie mogłem użyć CommandManager.InvalidateRequerySuggested();, ponieważ otrzymywałem wydajność.

Użyłem polecenia Delegowanie, które wygląda tak, jak poniżej (zmieniłem to nieco dla naszego polecenia). trzeba zadzwonić command.RaiseCanExecuteChanged() z VM

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

/// <summary> 
/// This method can be used to raise the CanExecuteChanged handler. 
/// This will force WPF to re-query the status of this command directly. 
/// </summary> 
public void RaiseCanExecuteChanged() 
{ 
    if (canExecute != null) 
     OnCanExecuteChanged(); 
} 

/// <summary> 
/// This method is used to walk the delegate chain and well WPF that 
/// our command execution status has changed. 
/// </summary> 
protected virtual void OnCanExecuteChanged() 
{ 
    EventHandler eCanExecuteChanged = _internalCanExecuteChanged; 
    if (eCanExecuteChanged != null) 
     eCanExecuteChanged(this, EventArgs.Empty); 
} 
+0

To działa lepiej dla mnie. Dzięki. –

+2

Tylko FYI skomentowałem CommandManager.RequerySuggested + = wartość; Otrzymałem prawie stałą/zapętloną ocenę mojego kodu CanExecute z jakiegoś powodu. W przeciwnym razie rozwiązanie działało zgodnie z oczekiwaniami. Dzięki! – robaudas

2

I zostały wdrożone rozwiązanie do obsługi zależność własności na polecenia, tutaj link https://stackoverflow.com/a/30394333/1716620

Dzięki temu będziesz skończyć o polecenie takiego:

this.SaveCommand = new MyDelegateCommand<MyViewModel>(this, 
    //execute 
    () => { 
     Console.Write("EXECUTED"); 
    }, 
    //can execute 
    () => { 
     Console.Write("Checking Validity"); 
     return PropertyX!=null && PropertyY!=null && PropertyY.Length < 5; 
    }, 
    //properties to watch 
    (p) => new { p.PropertyX, p.PropertyY } 
); 
4

Jeśli walcowane własne klasy, która implementuje ICommand można stracić dużo automatycznych aktualizacji statusu zmuszając polegać na ręcznym ochłody więcej niż powinna być konieczna. Może również złamać InvalidateRequerySuggested(). Problem polega na tym, że prosta implementacja ICommand nie łączy nowego polecenia z CommandManager.

Rozwiązaniem jest użycie następujących nośników:

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

    public void RaiseCanExecuteChanged() 
    { 
     CommandManager.InvalidateRequerySuggested(); 
    } 

ten sposób abonenci dołączyć do CommandManager zamiast swojej klasie, a może właściwie uczestniczyć w zmianach stanu dowodzenia.

+0

Prosto, do rzeczy i pozwala ludziom kontrolować ich implementacje ICommand. –