コマンドの CanExecute メソッドのプロパティを動作させるのに問題があります。コマンドを DataGrid 内のボタンにバインドしました。CommandParameter をボタンの DataContext にバインドしました。これはたまたま DataGrid の行のレコードです。
私が予想しているのは、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
}
MainWindow.xaml の 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>
サンプル コードを読み込むと、必要な行固有のデータではなく、各行で CanExecute メソッドがパラメーターとして null を受け取っているため、すべての [サインアウト] ボタンが無効になっていることがわかります。このサンプルが正常に機能していれば、最初はすべてのボタンが有効になり、[終了時間] 列の値が設定された後にのみ無効になります。