我无法获取命令的CanExecute方法来处理属性。我已将命令绑定到DataGrid内的按钮。我已将CommandParameter绑定到按钮的DataContext,它恰好是DataGrid中一行的记录。
我期望发生的是在CommandParameter绑定发生更改时重新评估CanExecute方法,在这种情况下,将设置行的DataContext属性。但是,不是针对行数据评估CanExecute方法,而是在行获取其DataContext之前评估CanExecute方法,并且在更新DataContext之后永远不会重新评估它。
你能告诉我如何根据每一行的DataContext来评估我的命令的CanExecute方法吗?
我已经创建了一个示例应用程序来演示我的问题。这是代码:
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作为参数而不是我想要的行特定数据。如果此示例工作正常,则最初将启用所有按钮,并且仅在设置“退出时间”列中的值后禁用。
答案 0 :(得分:2)
您没有正确设置自定义命令。在当前示例中,您不需要手动创建实现ICommand的命令,只需创建Routed或RoutedUI命令并连接相应的处理程序即可。删除SignOutCommand对象,然后修改您的Window代码,如下所示:
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如下(基本上,只需从Path中删除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时,您的注销按钮将正确启用。