2014-09-29 100 views
3

我正在學習WPF中的ICommands,並且遇到了一些簡單代碼的問題。我有一個帶命令的按鈕。如果我將命令參數設置爲像這樣的靜態值CommandParameter="100",則CanExecute中的參數parameter的值爲100,但是當我通過綁定來設置命令參數的值,例如CommandParameter="{Binding}"時,CanExecute中parameter參數的值一片空白。當我將CommandParameter設置爲某個Binding時,爲什麼我的ICommand.CanExecute(object)參數爲空,但當我將它設置爲某個靜態值時,它是非null?

這裏是我的ICommand:

internal class MyCommand : ICommand 
{ 
    public bool CanExecute(object parameter) //parameter is null 
    { 
     var datacontext = parameter as MyDataContext; 
     if (datacontext == null) 
      return false; 

     return datacontext.IsChecked == true; 
    } 

    public event EventHandler CanExecuteChanged; 

    public void Execute(object parameter) 
    { 
     throw new NotImplementedException(); 
    } 
} 

這裏的XAML代碼。請注意,我在設置Command之前設置了CommandParameter。我得到了那個from here。同樣,如果我將CommandParameter更改爲CommandParameter="100"之類的東西,則代碼的行爲與我預期的相同(即參數爲100,非空)。

<StackPanel Orientation="Vertical"> 
    <StackPanel.Resources> 
     <cmd:MyCommand x:Key="kCmd" /> 
    </StackPanel.Resources> 

    <CheckBox Content="Check this to enable button" IsChecked="{Binding IsChecked}" /> 
    <Button Content="Click" CommandParameter="{Binding}" 
      Command="{StaticResource kCmd}" /> 
</StackPanel> 

這是我的MainWindow代碼隱藏。在這裏,我在調用InitializeComponent()之前設置DataContext。在調試時,我發現InitializeComponent()觸發了對ICommand的CanExecute(object)的調用。

public MainWindow() 
{ 
    this.DataContext = new MyDataContext(); 
    InitializeComponent(); 
} 

我的MyDataContext類很簡單,所以我就把它排除了。

+0

您是否嘗試在'InitializeComponent'後面設置'DataContext'? – dkozl 2014-09-29 14:34:32

+0

@dkozl,我最初嘗試過。結果是一樣的。 – user2023861 2014-09-29 14:47:03

+0

我最好的猜測是在DataContext設置之前調用CanExecute的時機。您是否可以在加載完所有內容後測試CanExecute,例如當您單擊Button時? – Rachel 2015-12-02 16:12:56

回答

0

嘗試提高CanExecuteChanged - InitializeComponent()完成後MyCommand級的事件。可能調用CanExecute(object)MyCommand以在第一次渲染時初始化按鈕的狀態,而綁定尚未初始化。

+0

我試圖通過給按鈕一個名稱並調用'this.btn.Command.CanExecute(this.DataContext)'。兩個問題:(1)這似乎避免了這個問題,因爲綁定仍然存在問題。 (2)這看起來不像MVVM解決方案。在ViewModel中給按鈕一個名字並引用它,會引起ViewModel和View之間更緊密的耦合。我想避免這種情況。 – user2023861 2014-09-29 14:59:16

+0

對不起,但我的意思是在您的ViewModel中引發MyCommand.CanExecuteChanged事件 - 不是顯式地(重新)調用Button的CanExecute()方法。 CanExecuteChanged事件將通過調用MyCommand上的CanExecute(object)來觸發按鈕來刷新它的狀態,然後通過正確的DataContext傳遞給你的類。 – 2014-09-29 15:06:49

+0

糟糕。我誤讀了。我現在在MainWindow構造函數中調用'(this.btn.Command as MyCommand).RaiseCanExecuteChanged();'。一旦被調用,參數就是我所期望的。在CanExecute(object)中,我掛接到MydataContext.PropertyChanged處理程序並適當地調用'RaiseCanExecuteChanged()'。現在這一切都有效。告訴我,這是連接一個ICommand工具的首選方式嗎? 'RaiseCanExecuteChanged()'部分看起來很多。 – user2023861 2014-09-29 15:31:39

2

這也是通過提高命令的CanExecuteChanged事件來強制重新評估CanExecuteFrameworkElement事件的Loaded的解決方案。當您使用DataTemplate s時,此方法尤其可以使用,並且您遇到此問題。

實施例:

<DataTemplate x:Key="MyTemplate"> 
      <Grid Loaded="HandleLoaded"> 
... 

和代碼後面:

void HandleLoaded(object sender, RoutedEventArgs e) 
{ 
    var viewModel = this.DataContext as ViewModel; 
    if (viewModel != null) 
    { 
     viewModel.DoItCommand.RaiseCanExecuteChanged(); 
    } 
} 

另一種可能的解決方案,其可以作品,是定義的結合於該命令本身作爲IsAsync=True。但是這會導致一些閃爍。所以它可能不是最好的選擇。

例如:{Binding DoItCommand, IsAsync=True}

相關問題