2013-02-22 10 views
8

Mam proste okno z przyciskiem związanym z ViewModel za pomocą polecenia.Przycisk nie wyłącza się, gdy polecenie CanExecute jest fałszywe.

Oczekuję, że przycisk zostanie wyłączony, jeśli funkcja MyCommand.CanExecute() ma wartość false. Wygląda jednak na to, że WPF ustawi właściwość IsEnabled tylko wtedy, gdy okno zostanie najpierw narysowane. Każde kolejne działanie nie wpływa na widoczny stan przycisku. Używam DelegateCommand od Prism.

moim zdaniem:

<Window x:Class="WpfApplication1.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="MainWindow" Height="350" Width="525"> 
<Grid> 
    <Button Content="Click Here" Command="{Binding MyCommand}" Width="100" Height="50"/> 
</Grid> 

i mój ViewModel:

public class MyVM : NotificationObject 
{ 
    public MyVM() 
    { 
     _myCommand = new DelegateCommand(DoStuff, CanDoStuff); 
    } 

    private void DoStuff() 
    { 
     Console.WriteLine("Command Executed"); 
     _myCommand.RaiseCanExecuteChanged(); 
    } 

    private bool CanDoStuff() 
    { 
     var result = DateTime.Now.Second % 2 == 0; 
     Console.WriteLine("CanExecute is {0}", result); 
     return result; 
    } 

    private DelegateCommand _myCommand; 

    public ICommand MyCommand 
    { 
     get 
     { 
      return _myCommand; 
     } 
    } 
} 

50% czasu, kiedy moi ładowania aplikacji, przycisk zostanie prawidłowo wyłączony. Jeśli jednak jest włączona, gdy okno się wczytuje, a kliknę przycisk, aby wykonać polecenie, oczekuję 50% czasu na wyłączenie przycisku, ale nigdy tak nie jest. Polecenie nie jest wykonywane, ale nadal mogę kliknąć przycisk. W jaki sposób uzyskać WPF, aby zrozumieć, że przycisk powinien być wyłączony, gdy CanExecute() jest false?

+0

Pierwszą rzeczą, którą musisz zrobić, to pojawić się komunikaty debugowania dla wiązania z danymi: http://i.stack.imgur.com/MF8i5.png Następnie ponownie uruchom i sprawdź okno wyjściowe i zobacz, jakie są błędy. Jeśli żadna nie odnosi się do twojego powiązania poleceń, twoja implementacja 'RaiseCanExecuteChanged()' jest niepoprawna/błędna. – Will

+0

Twoja metoda CanDOStuff jest naprawdę dziwna! Może to spowodować, że twój przycisk zostanie wyłączony, ale w następnej sekundzie polecenie może zostać wykonane, ale przycisk jest wyłączony ... Naprawdę dziwne. ale powinieneś zadzwonić do [CommandManager.InvalidateRequerySuggested()] (http://msdn.microsoft.com/en-us/library/system.windows.input.commandmanager.invalidaterequerysuggested.aspx) jeśli twoja CanExecute może zostać zmieniona, a interfejs użytkownika nie jest zmieniony zaktualizowany, ponieważ CanExecuteChanged nie został podniesiony. –

+0

@Viktor Wiem, że to naprawdę dziwne, ma to być głupi przykład, który zwraca losowo wartość true/false. CommandManager.InvalidateRequerySuggested nie ma żadnego efektu. –

Odpowiedz

6

Widzę, że używasz Prism i jego NotificationObject i DelegateCommand, więc powinniśmy się spodziewać, że nie będzie błędu w RaiseCanExecuteChanged().

Powodem tego zachowania jest to, że RaiseCanExecuteChanged Prism'a działa synchronicznie, więc CanDoStuff() jest wywoływane, dopóki nadal jesteśmy w implementacji ICommand.Execute(), a wynik wydaje się być ignorowany.

Jeśli utworzysz inny przycisk z własnym rozkazem i wywołasz _myCommand.RaiseCanExecuteChanged() z tego polecenia/przycisku, pierwszy przycisk zostanie włączony/wyłączony zgodnie z oczekiwaniami.

Lub, jeśli spróbujesz to samo z MVVM Światła i RelayCommand kod zadziała, ponieważ MVVM Light RaiseCanExecuteChanged rozmowy CommandManager.InvalidateRequerySuggested() który wywołuje oddzwanianie do CanDoStuff asynchronicznie za pomocą Dispatcher.CurrentDispatcher.BeginInvoke, unikanie zachowań jesteś widząc z realizacją Prism.

+0

Dzięki za wyjaśnienie. Próbowałem obu twoich sugestii i są na miejscu. Wydaje się niefortunnym ograniczeniem Prism. –

0

Można spróbować to (Microsoft.Practices.Prism.dll jest konieczne)

public class ViewModel 
{ 
    public DelegateCommand ExportCommand { get; } 

    public ViewModel() 
    { 
     ExportCommand = new DelegateCommand(Export, CanDoExptor); 
    } 

    private void Export() 
    { 
     //logic 
    } 

    private bool _isCanDoExportChecked; 

    public bool IsCanDoExportChecked 
    { 
     get { return _isCanDoExportChecked; } 
     set 
     { 
      if (_isCanDoExportChecked == value) return; 

      _isCanDoExportChecked = value; 
      ExportCommand.RaiseCanExecuteChanged(); 
     } 
    } 

    private bool CanDoExptor() 
    { 
     return IsCanDoExportChecked; 
    } 
} 
Powiązane problemy