WPF 在添加新行之前禁用与 DataGrid 的 TemplateColumn 交互

WPF disable interacting with DataGrid's TemplateColumn for new rows before they are added

考虑具有 DataGridTemplateColumn(s) 的 WPF DataGrid 并且允许用户启动添加 CanUserAddRows="True",例如

<DataGrid AutoGenerateColumns="False" CanUserAddRows="True" ItemsSource="{Binding Options}">
    <DataGrid.Columns>
        <DataGridTemplateColumn>
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <RadioButton IsChecked="{Binding IsChecked}" GroupName="OptionsRad"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
        <DataGridTextColumn Header="Option" Binding="{Binding OptionName}"/>
    </DataGrid.Columns>
</DataGrid>

RadioButton 由于托管 DataGridTemplateColumn 可以在不进入 CellEditingMode 的情况下进行交互,这是预期和期望的。
然而,问题是在最后一个 'add new option' 行类型 RadioButton 甚至可以在添加新选项 之前与 进行交互(即将添加名称输入)。可能选择不存在的选项并将焦点转移到其他地方。

在将新行添加到绑定集合之前,如何禁用与模板列的交互?

您可以使用转换器来实现您的目标。

我假设您有一个 class 或数据类型来表示您的 Option 数据,并且 Options 是这些项目的集合。

您可以将 RadioButton 上的 IsEnabled 设置为:

IsEnabled="{Binding Path=Item, RelativeSource={RelativeSource AncestorType=DataGridRow"}, Converter={StaticResource DataToEnabledConverter}}"

而且,转换器代码如下所示:

public class DataToEnabledConverter : IValueConverter
{
     public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
     {
         return value is Option;
     }

     public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
     {
         throw new NotImplementedException();
     }
}

你的完整 XAML 看起来像:

    <DataGrid AutoGenerateColumns="False" CanUserAddRows="True" ItemsSource="{Binding Options}">
        <DataGrid.Columns>
            <DataGridTemplateColumn>
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <RadioButton IsChecked="{Binding IsChecked}" GroupName="OptionsRad" 
                                     IsEnabled="{Binding Path=Item, RelativeSource={RelativeSource AncestorType=DataGridRow"}, Converter={StaticResource DataToEnabledConverter}}"/>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
            <DataGridTextColumn Header="Option" Binding="{Binding OptionName}"/>
        </DataGrid.Columns>
    </DataGrid>

之所以有效,是因为 DataGridRow 上的 Item 属性 新行的类型是 NamedObject,而不是您的数据类型。

你也可以和NewItemPlaceholderpurely in XAML比较:

<DataTemplate>
    <RadioButton x:Name="Radio" IsChecked="{Binding IsChecked}" GroupName="OptionsRad" />
    <DataTemplate.Triggers>
        <DataTrigger Binding="{Binding Item, RelativeSource={RelativeSource FindAncestor, AncestorType=DataGridRow}}"
                     Value="{x:Static CollectionView.NewItemPlaceholder}">
            <Setter TargetName="Radio" Property="IsEnabled" Value="False" />
        </DataTrigger>
    </DataTemplate.Triggers>
</DataTemplate>