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
,而不是您的数据类型。
你也可以和NewItemPlaceholder
purely 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>
考虑具有 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
,而不是您的数据类型。
你也可以和NewItemPlaceholder
purely 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>