0

我正在使用Microsoft.Toolkit.Mvvm nuget 包在 .NET Core 3.1 上构建 WPF 应用程序。

我在绑定 Datagrid 的 DataGridTemplateColumn 中的按钮的 CommandParameter 时遇到问题。

我在我的视图模型上定义了一个 RelayCommand,使用 IRelayCommand,并定义了一个带有参数的 CanExecute 方法。然后,我将按钮绑定的 CommandParameter 绑定到数据网格行的数据。

在运行时,我看到我的数据网格的每一行都调用了 CanExecute 方法,但是参数值始终为空。如果我的 ObservableCollection 中有 5 个项目,我会看到 CanExecute 被调用了 5 次,3 个项目...... 3 次。在所有情况下,该值为空。

下面是用于创建 TestModel 类型的 ObservableCollection 的视图模型的代码。创建了一个 RelayCommand,CanExecute 的标准被简化为仅比较数据绑定模型的 name 属性。

我在这里期望的是,对于除名称为“Test2”的行之外的所有行,绑定按钮都将被启用。Test2 行中的按钮将被禁用。

这是我的视图模型和相关的模型类。

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;
}

还有我的 Datagrid 的 xaml

<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 工具包之间有什么不同吗?

您可以提供的任何帮助或指导将不胜感激,谢谢。

4

1 回答 1

1

我在这里想念什么?

CanExecute在设置之前调用的事实CommandParameter

将绑定更改为此似乎对我有用:

CommandParameter="{Binding DataContext, RelativeSource={RelativeSource Self}}"

另请注意,除非您将CanUserAddRows属性设置为DataGridto 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;
}
于 2022-01-27T19:37:55.203 回答