在 DataGrid 中进行数据绑定时,CommandParameter 未传递给 CanExecute(CanExecute 参数为空)
CommandParameter not passed to CanExecute when databound within a DataGrid (CanExecute parameter is null)
我正在使用 Microsoft.Toolkit.Mvvm nuget 包在 .NET Core 3.1 上构建 WPF 应用程序。
我在将按钮的 CommandParameter 绑定到 Datagrid 的 DataGridTemplateColumn 中时遇到问题。
我使用 IRelayCommand 在我的视图模型上定义了一个 RelayCommand,并且定义了一个带有参数的 CanExecute 方法。然后我将按钮绑定的 CommandParameter 绑定到数据网格行的数据。
在运行时,我看到我的数据网格的每一行都调用了 CanExecute 方法,但参数值始终为空。如果我的 ObservableCollection 中有 5 个项目,我会看到 CanExecute 被调用了 5 次,3 个项目...... 3 次。在所有情况下,该值为空。
下面是我的视图模型的代码,它创建了一个 TestModel 类型的 ObservableCollection。 RelayCommand 被创建,CanExecute 的标准简化为只比较数据绑定模型的名称 属性。
我在这里期望的是,对于除名称为“Test2”的行之外的所有行,绑定按钮都将启用。 Test2 行中的按钮将被禁用。
这是我的视图模型和相关模型 class。
public class MainWindowVM : ObservableObject, IViewModel
{
public MainWindowVM()
{
TestData = new ObservableCollection<TestModel>
{
new TestModel() {Name = "Test1"},
new TestModel() {Name = "Test2"},
new TestModel() {Name = "Test3"}
};
DeleteCommand = new RelayCommand<TestModel>(Delete, CanDelete);
}
public IRelayCommand<TestModel> DeleteCommand { get; }
private void Delete(TestModel model)
{
//do stuff
}
private bool CanDelete(TestModel model)
{
if (model.Name == "Test2")
{
return false;
}
return true;
}
public ObservableCollection<TestModel> TestData
{
get => _testData;
set => SetProperty(ref _testData, value);
}
private ObservableCollection<TestModel> _testData;
}
public class TestModel : ObservableObject
{
public string Name
{
get => _name;
set => SetProperty(ref _name, value);
}
private string _name;
}
还有我的 xaml Datagrid
<Grid>
<DataGrid ItemsSource="{Binding Path=TestData}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Username"
Binding="{Binding Path=Name}"
MinWidth="180" />
<DataGridTemplateColumn Header="" Width="160">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Button Command="{Binding Path=DataContext.DeleteCommand, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"
CommandParameter="{Binding}" Content="Delete"
Width="100" >
</Button>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
我在这里错过了什么?
我在其他 WPF 应用程序中无数次使用过这种方法。这是我第一次使用这个工具包(我以前使用过 MVVMLight),也是第一次在 .NET Core 上构建 WPF。
这是 .NET Core 上 WPF 的变化吗?两个 MVVM 工具包之间有什么不同吗?
如果您能提供任何帮助或指导,我们将不胜感激,谢谢。
What am I missing here?
在设置 CommandParameter
之前调用 CanExecute
的事实。
更改对此的绑定似乎对我有用:
CommandParameter="{Binding DataContext, RelativeSource={RelativeSource Self}}"
另请注意,除非您将 DataGrid
的 CanUserAddRows
属性 设置为 false
,否则您的 CanDelete
也将使用 MS.Internal.NamedObject
这将导致应用程序崩溃,除非您更改 RelayCommand
:
的类型参数
public class MainWindowVM : ObservableObject
{
public MainWindowVM()
{
TestData = new ObservableCollection<TestModel>
{
new TestModel() {Name = "Test1"},
new TestModel() {Name = "Test2"},
new TestModel() {Name = "Test3"}
};
DeleteCommand = new RelayCommand<object>(Delete, CanDelete);
}
public IRelayCommand<object> DeleteCommand { get; }
private void Delete(object parameter)
{
if (parameter is TestModel model)
{
//do stuff
}
}
private bool CanDelete(object parameter)
{
if (parameter is TestModel model && model.Name == "Test2")
{
return false;
}
return true;
}
public ObservableCollection<TestModel> TestData
{
get => _testData;
set => SetProperty(ref _testData, value);
}
private ObservableCollection<TestModel> _testData;
}
我正在使用 Microsoft.Toolkit.Mvvm nuget 包在 .NET Core 3.1 上构建 WPF 应用程序。
我在将按钮的 CommandParameter 绑定到 Datagrid 的 DataGridTemplateColumn 中时遇到问题。
我使用 IRelayCommand 在我的视图模型上定义了一个 RelayCommand,并且定义了一个带有参数的 CanExecute 方法。然后我将按钮绑定的 CommandParameter 绑定到数据网格行的数据。
在运行时,我看到我的数据网格的每一行都调用了 CanExecute 方法,但参数值始终为空。如果我的 ObservableCollection 中有 5 个项目,我会看到 CanExecute 被调用了 5 次,3 个项目...... 3 次。在所有情况下,该值为空。
下面是我的视图模型的代码,它创建了一个 TestModel 类型的 ObservableCollection。 RelayCommand 被创建,CanExecute 的标准简化为只比较数据绑定模型的名称 属性。
我在这里期望的是,对于除名称为“Test2”的行之外的所有行,绑定按钮都将启用。 Test2 行中的按钮将被禁用。
这是我的视图模型和相关模型 class。
public class MainWindowVM : ObservableObject, IViewModel
{
public MainWindowVM()
{
TestData = new ObservableCollection<TestModel>
{
new TestModel() {Name = "Test1"},
new TestModel() {Name = "Test2"},
new TestModel() {Name = "Test3"}
};
DeleteCommand = new RelayCommand<TestModel>(Delete, CanDelete);
}
public IRelayCommand<TestModel> DeleteCommand { get; }
private void Delete(TestModel model)
{
//do stuff
}
private bool CanDelete(TestModel model)
{
if (model.Name == "Test2")
{
return false;
}
return true;
}
public ObservableCollection<TestModel> TestData
{
get => _testData;
set => SetProperty(ref _testData, value);
}
private ObservableCollection<TestModel> _testData;
}
public class TestModel : ObservableObject
{
public string Name
{
get => _name;
set => SetProperty(ref _name, value);
}
private string _name;
}
还有我的 xaml Datagrid
<Grid>
<DataGrid ItemsSource="{Binding Path=TestData}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Username"
Binding="{Binding Path=Name}"
MinWidth="180" />
<DataGridTemplateColumn Header="" Width="160">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Button Command="{Binding Path=DataContext.DeleteCommand, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"
CommandParameter="{Binding}" Content="Delete"
Width="100" >
</Button>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
我在这里错过了什么? 我在其他 WPF 应用程序中无数次使用过这种方法。这是我第一次使用这个工具包(我以前使用过 MVVMLight),也是第一次在 .NET Core 上构建 WPF。 这是 .NET Core 上 WPF 的变化吗?两个 MVVM 工具包之间有什么不同吗?
如果您能提供任何帮助或指导,我们将不胜感激,谢谢。
What am I missing here?
在设置 CommandParameter
之前调用 CanExecute
的事实。
更改对此的绑定似乎对我有用:
CommandParameter="{Binding DataContext, RelativeSource={RelativeSource Self}}"
另请注意,除非您将 DataGrid
的 CanUserAddRows
属性 设置为 false
,否则您的 CanDelete
也将使用 MS.Internal.NamedObject
这将导致应用程序崩溃,除非您更改 RelayCommand
:
public class MainWindowVM : ObservableObject
{
public MainWindowVM()
{
TestData = new ObservableCollection<TestModel>
{
new TestModel() {Name = "Test1"},
new TestModel() {Name = "Test2"},
new TestModel() {Name = "Test3"}
};
DeleteCommand = new RelayCommand<object>(Delete, CanDelete);
}
public IRelayCommand<object> DeleteCommand { get; }
private void Delete(object parameter)
{
if (parameter is TestModel model)
{
//do stuff
}
}
private bool CanDelete(object parameter)
{
if (parameter is TestModel model && model.Name == "Test2")
{
return false;
}
return true;
}
public ObservableCollection<TestModel> TestData
{
get => _testData;
set => SetProperty(ref _testData, value);
}
private ObservableCollection<TestModel> _testData;
}