2013-01-12 74 views
26

在演示中,我有一個按鈕來切換布爾字段isAsking。我創建了一個只有在isAsking==true時才能執行的命令。何時調用CanExecute?

一旦我按下切換按鈕,okButton.IsEnable立即變化,這表示命令發現變化isAsking

我覺得很困惑,爲什麼命令對象會注意到字段的變化,當調用CanExecute

雖然寫了一段時間的WPF應用程序,但我是WPF Command的新手。請給出一個解釋,如果可能的話,指出一些相關的文章或博客(我已經閱讀了太多關於剪切/粘貼命令的文章)。

<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> 

代碼隱藏:

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; 
    } 
} 

回答

23

我嘗試搜索「的命令管理檢測條件」,達到this exellent article重新查詢CanExecute,你可以做。

通過檢查.NET Framework源代碼,作者認爲,CommandManager本身不檢測的條件下,而不是當Keyboard.KeyUpEventMouse.MouseUpEventKeyboard.GotKeyboardFocusEvent,或Keyboard.LostKeyboardFocusEvent發生時,它會重新評估CanExecute方法。

該文章包含其他信息,但以上部分對我來說已經夠用了。

+6

I對這種默認行爲有點驚駭。如果一個表單有很多控件,並且CanExecute方法寫得不是最佳的,那麼這是一個非常大的可能無用的CanExecute評估,不是嗎?無法看到架構如何擴展? – Shiv

27

的技術答案是,每當CommandManager.RequerySuggested事件引發CanExecute將被調用。根據文檔,這將是...

...當CommandManager檢測到條件可能會改變命令的執行能力。

實際上,這只是意味着你不需要擔心什麼時候CanExecute叫:當它認爲它是合適的WPF將調用它,在我的經驗,這將幾乎總是涉及您的要求。

這是一個例外,如果你有一個後臺任務將導致CanExecute改變它的返回值的基礎上,不是由用戶界面觸發的東西。在這種情況下,你可能需要手動強制WPF運行時通過調用CommandManager.InvalidateRequerySuggested

+6

或者如果它是一個Prism'DelegateCommand',則調用'Command'本身的'RaiseCanExecuteChanged()'。 – Default

+4

@默認正確。同樣,如果它是你自己的'ICommand'實現,你可以在命令 –

+0

Doyyy上手動提升'CanExecuteChanged'事件。我完全忘記了'ICommand'中的那個事件。在這裏我認爲Prism正在做些什麼:) – Default

8

RoutedCommand包含事件CanExecuteChanged在內部鉤到CommandManager.RequerySuggested事件 - 每當由命令 管理器,它是檢測到命令源改變

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

CommandManager.RequerySuggested事件引發

在你的情況是Window。所以,當點擊按鈕時,commandManager引發了RequerySuggested事件,並因此執行了爲您的命令註冊的CanExecute謂詞。

另外,CommandManager有一個靜態方法 - InvalidateRequerySuggested,它強制CommandManager引發RequerySuggestedEvent。所以,你可以調用它來手動驗證你的命令。