Mam Menu
gdzie każdy MenuItem
w hierarchii ma swoją Command
właściwość ustawioną na RoutedCommand
zdefiniowaną przeze mnie. Skojarzony CommandBinding
zapewnia wywołanie zwrotne do oceny, CanExecute
które kontroluje stan włączenia każdego MenuItem
.
To prawie działa. Pozycje menu początkowo pojawiają się z prawidłowymi stanami włączenia i wyłączenia. Jednak gdy dane, których CanExecute
używa moje wywołanie zwrotne, ulegną zmianie, potrzebuję polecenia, aby ponownie zażądać wyniku z mojego wywołania zwrotnego, aby ten nowy stan został odzwierciedlony w interfejsie użytkownika.
Tam nie wydają się być wszelkie metody publiczne na RoutedCommand
lub CommandBinding
za to.
Zwróć uwagę, że wywołanie zwrotne jest używane ponownie, gdy klikam lub piszę w kontrolce (myślę, że jest wyzwalane przy wprowadzaniu danych, ponieważ najechanie kursorem myszy nie powoduje odświeżenia).
źródło
Dla każdego, kto zetknie się z tym później; Jeśli używasz MVVM i Prism,
DelegateCommand
implementacja PrismICommand
zapewnia.RaiseCanExecuteChanged()
metodę, aby to zrobić.źródło
RaiseCanExecuteChanged()
proste wywołaniaCommandManager.InvalidateRequerySuggested()
.((RelayCommand)MyCommand).RaiseCanExecuteChanged();
działało dla mnie, używając GalaSoft.MvvmLight.Command - ALE po zmianie naCommandWPF
działało bez potrzeby dzwonienia do czegokolwiek. Dzięki @ fuchs777Nie mogłem użyć,
CommandManager.InvalidateRequerySuggested();
ponieważ dostałem hit wydajności.Użyłem polecenia delegowania MVVM Helpera , które wygląda jak poniżej (trochę go poprawiłem dla naszego wymagania). musisz zadzwonić
command.RaiseCanExecuteChanged()
z VMpublic 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); }
źródło
Jeśli wyrzuciłeś swoją własną klasę, która implementuje
ICommand
, możesz stracić wiele automatycznych aktualizacji statusu, zmuszając cię do polegania na ręcznym odświeżaniu bardziej niż powinno. Może też pęknąćInvalidateRequerySuggested()
. Problem polega na tym, że prostaICommand
implementacja nie łączy nowego polecenia z plikiemCommandManager
.Rozwiązaniem jest użycie:
public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } public void RaiseCanExecuteChanged() { CommandManager.InvalidateRequerySuggested(); }
W ten sposób subskrybenci przyłączają się do
CommandManager
Twojej klasy, a nie do Twojej klasy i mogą odpowiednio uczestniczyć w zmianach statusu poleceń.źródło
Zaimplementowałem rozwiązanie do obsługi zależności właściwości od poleceń, tutaj link https://stackoverflow.com/a/30394333/1716620
dzięki temu otrzymasz takie polecenie:
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 } );
źródło
Oto, co zadziałało dla mnie: umieść CanExecute przed poleceniem w kodzie XAML.
źródło