2016-08-13 67 views
1

問題:按鈕永遠不會啓用。按鈕保持禁用 - DelegateCommand不重新評估CanExecute處理程序

<Button Name="btnCompareAxises"Command="{Binding CompareCommand}" 
      Content="{Binding VM.CompareAxisButtonLabel}" 
     IsEnabled="{Binding VM.IsCompareButtonEnabled}"> 
</Button> 

視圖模型構造:

this.CompareCommand = new DelegateCommand(CompareCommand, ValidateCompareCommand); 

這個問題似乎涉及到按鈕的登記命令的CanExecute事件處理程序。 當應用程序加載時,CanExecute處理程序返回false。 這很好,因爲最初沒有滿足條件。

canExecute處理程序僅在應用程序啓動時或單擊按鈕時運行。您無法單擊禁用的按鈕,因此如果從CanExecute處理程序返回的初始值爲false,該按鈕將永遠保持禁用狀態!

問:
我必須再次啓用按鈕,只使用綁定到它的命令。 有點像,嘿命令請重新評估,如果這個按鈕的條件滿足?

爲什麼坐在部分強制下的IsEnabled屬性而不是在本地?

enter image description here

命令:

public class DelegateCommand : ICommand 
{ 
    private readonly Func<object, bool> canExecute; 
    private readonly Action<object> execute; 

    public DelegateCommand(Action<object> execute, Func<object, bool> canExecute = null) 
    { 
     this.execute = execute; 
     this.canExecute = canExecute; 
    } 

    public event EventHandler CanExecuteChanged; 

    public bool CanExecute(object parameter) 
    { 
     return this.canExecute == null || this.canExecute(parameter); 
    } 

    public void Execute(object parameter) 
    { 
     this.execute(parameter); 
    } 

    public void RaiseCanExecuteChanged() 
    { 
     this.OnCanExecuteChanged(); 
    } 

    protected virtual void OnCanExecuteChanged() 
    { 
     var handler = this.CanExecuteChanged; 
     if (handler != null) 
     { 
      handler(this, EventArgs.Empty); 
     } 
    } 
} 
+1

如果您已經綁定到通過CanExecute實現類似行爲的命令,是否需要綁定IsEnabled? – stijn

+0

不,我現在將其刪除,該按鈕將被自動禁用,不需要額外的綁定。謝謝 ! – Legends

回答

1

解決:

我不得不適應DelegateCommand類,使其工作:

我已經加入CommandManager.RequerySuggested到公衆CanExecuteChanged活動屬性。

現在當用戶界面發生變化時,它會自動重新評估命令的CanExecute方法!

public class DelegateCommand : ICommand 
{ 
    private readonly Func<object, bool> canExecute; 
    private readonly Action<object> execute; 

    public DelegateCommand(Action<object> execute, Func<object, bool> canExecute = null) 
    { 
     this.execute = execute; 
     this.canExecute = canExecute; 
    } 

    /// CommandManager 
    /// Go to the "References" part of your class library and select "Add Reference". 
    /// Look for an assembly called "PresentationCore" and add it. 
    public event EventHandler CanExecuteChanged 
    { 
     add 
     { 
      _internalCanExecuteChanged += value; 
      CommandManager.RequerySuggested += value; 

     } 
     remove 
     { 
      _internalCanExecuteChanged -= value; 
      CommandManager.RequerySuggested -= value; 
     } 
    } 

    event EventHandler _internalCanExecuteChanged; 

    public bool CanExecute(object parameter) 
    { 
     return this.canExecute == null || this.canExecute(parameter); 
    } 

    public void Execute(object parameter) 
    { 
     this.execute(parameter); 
    } 

    public void RaiseCanExecuteChanged() 
    { 
     this.OnCanExecuteChanged(); 
    } 

    protected virtual void OnCanExecuteChanged() 
    { 
     var handler = this._internalCanExecuteChanged; 
     if (handler != null) 
     { 
      handler(this, EventArgs.Empty); 
     } 
    } 
} 

從按鈕移除了這個:

IsEnabled="{Binding VM.IsCompareButtonEnabled}" 

的結合在這裏是沒有必要的,因爲CanExecute處理程序會照顧按鈕的啓用/禁用狀態的!

+0

CommandManager真的不是這樣的最佳解決方案,因爲不是一個按鈕檢查是否可以執行,*所有按鈕都會*。您將阻止UI線程,直到他們全部執行檢查,因此您擁有的線程越多,重新評估其狀態的時間越長,UI鎖定的時間就越長。更好的辦法就是讓你的ICommand公開一個你可以觸發CanExecuteChanged事件的方法。擁有的ViewModel應該準確知道該命令何時可用,並且可以在其運行時向其觀察者發出信號。 – Will

+0

@威爾,這是我第一週與WPF。感謝您的評論。 我想,CanExecute完全是爲了這個目的,如果CanExecute驗證成功,禁用/啓用命令按鈕。我的GUI上有兩個使用CanExecute處理程序的按鈕。我添加了一些跟蹤,我可以看到每次點擊鼠標或按鍵都會觸發這兩個處理程序的執行。 但是,如果我接管啓動/停用按鈕的責任,我必須在每次按鍵時檢查它。 – Legends

+1

當然,我可以使它變得非常簡單,並且只在點擊按鈕並顯示消息時驗證GUI :-)它是一個小應用程序,因此它不會受到太大傷害。 但好點!總結一下,不要將CommandManager與CanExecute結合使用。 人們應該在需要時手動調用它。 – Legends