2012-06-29 87 views
1

我無法讓我的命令的CanExecute方法工作屬性。我已經綁定了一個命令到一個DataGrid中的按鈕。我已經將CommandParameter綁定到按鈕的DataContext上,這恰好是DataGrid中的一行記錄。WPF命令CanExecute在DataContext更改時未被重新評估

我希望發生的是在CommandParameter綁定更改時重新評估CanExecute方法,在此情況下,該方法將設置行的DataContext屬性。但不是針對行數據評估CanExecute方法,而是在行獲取其DataContext之前對CanExecute方法進行評估,並且在更新DataContext之後不會重新評估該方法。

你能告訴我如何讓我的命令的CanExecute方法根據每行的DataContext進行評估嗎?

我創建了一個示例應用程序來演示我的問題。下面的代碼:

代碼隱藏在MainWindow.xaml

public partial class MainWindow : Window 
{ 
    public ObservableCollection<LogRecord> Records { get; private set; } 
    public ICommand SignOutCommand { get; private set; } 
    public MainWindow() 
    { 
     InitializeComponent(); 
     DataContext = this; 
     Records = new ObservableCollection<LogRecord>(); 
     SignOutCommand = new SignOutCommand(); 
     CreateDemoData(); 
    } 
    private void CreateDemoData() 
    { 
     for (int i = 0; i < 5; i++) 
     { 
      Records.Add(new LogRecord()); 
     } 
    } 
} 

public class LogRecord : INotifyPropertyChanged 
{ 
    private DateTime _EntryTime; 
    public DateTime EntryTime 
    { 
     get { return _EntryTime; } 
     set 
     { 
      if (_EntryTime == value) return; 
      _EntryTime = value; 
      RaisePropertyChanged("EntryTime"); 
     } 
    } 

    private DateTime? _ExitTime; 
    public DateTime? ExitTime 
    { 
     get { return _ExitTime; } 
     set 
     { 
      if (_ExitTime == value) return; 
      _ExitTime = value; 
      RaisePropertyChanged("ExitTime"); 
     } 
    } 

    public LogRecord() 
    { 
     EntryTime = DateTime.Now; 
    } 

    #region Implementation of INotifyPropertyChanged 

    public event PropertyChangedEventHandler PropertyChanged; 

    public void RaisePropertyChanged(string propertyName) 
    { 
     if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
    } 

    #endregion 
} 

public class SignOutCommand : ICommand 
{ 
    #region Implementation of ICommand 

    public void Execute(object parameter) 
    { 
     var record = parameter as LogRecord; 
     if (record == null) return; 
     record.ExitTime = DateTime.Now; 
    } 

    public bool CanExecute(object parameter) 
    { 
     var record = parameter as LogRecord; 
     return record != null && !record.ExitTime.HasValue; 
    } 

    public event EventHandler CanExecuteChanged; 

    #endregion 
} 

的XAML爲MainWindow.xaml

<Window x:Class="Command_Spike.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="MainWindow" 
    Width="525" 
    Height="350"> 
<DataGrid ItemsSource="{Binding Path=Records}" IsReadOnly="True" AutoGenerateColumns="False"> 
    <DataGrid.Columns> 
     <DataGridTextColumn Header="Entry Time" Binding="{Binding Path=EntryTime}" /> 
     <DataGridTextColumn Header="Exit Time" Binding="{Binding Path=ExitTime}" /> 
     <DataGridTemplateColumn> 
      <DataGridTemplateColumn.CellTemplate> 
       <DataTemplate> 
        <Button Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, 
                      AncestorType=Window}, 
               Path=DataContext.SignOutCommand}" 
          CommandParameter="{Binding}" 
          Content="Sign Out" /> 
       </DataTemplate> 
      </DataGridTemplateColumn.CellTemplate> 
     </DataGridTemplateColumn> 
    </DataGrid.Columns> 
</DataGrid> 

如果加載了示例代碼中,您可以看到所有註銷按鈕都被禁用,因爲在每一行CanEx中都是如此ecute方法接收空值作爲參數,而不是我想要的行特定數據。如果此示例工作正常,則最初將啓用所有按鈕,並且只有在設置了退出時間列中的值後纔會禁用。

回答

2

您沒有正確設置自定義命令。在您當前的示例中,您不需要手動創建實現ICommand的命令,只需創建RoutedUI或RoutedUI命令並連接適當的處理程序即可。刪除你的SignOutCommand對象,然後修改你的窗口如下代碼:

public partial class MainWindow: Window 
{ 
    public ObservableCollection<LogRecord> Records { get; private set; } 
    public static RoutedUICommand SignOutCommand { get; private set; } 

    public MainWindow() 
    { 
     InitializeComponent(); 
     DataContext = this; 
     Records = new ObservableCollection<LogRecord>(); 
     CreateDemoData(); 

     SignOutCommand = new RoutedUICommand(); 
     CommandBinding cb = new CommandBinding(SignOutCommand, OnSignOut, OnCanSignOut); 
     this.CommandBindings.Add(cb); 
    } 


    private void CreateDemoData() 
    { 
     for (int i = 0; i < 5; i++) 
     { 
      Records.Add(new LogRecord()); 
     } 
    } 

    private void OnCanSignOut(object sender, CanExecuteRoutedEventArgs e) 
    { 
     var record = e.Parameter as LogRecord; 
     e.CanExecute = record != null && !record.ExitTime.HasValue; 

    } 

    private void OnSignOut(object sender, ExecutedRoutedEventArgs e) 
    { 
     var record = e.Parameter as LogRecord; 
     if (record == null) return; 
     record.ExitTime = DateTime.Now; 
    } 
} 

然後,修改您的DataTemplate像如下(基本上,只是從路徑中刪除的DataContext):

<dg:DataGridTemplateColumn> 
    <dg:DataGridTemplateColumn.CellTemplate> 
    <DataTemplate> 
     <Button Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}, Path=SignOutCommand}" CommandParameter="{Binding}" Content="Sign Out" /> 
    </DataTemplate> 
    </dg:DataGridTemplateColumn.CellTemplate> 
</dg:DataGridTemplateColumn> 

使用這種方法當設置DataContext時,您的註銷按鈕將被正確啓用。

+0

完美。謝謝! –