我有一个卷曲的问题,我找不到任何完整和明确的信息......
我的要求很简单:我想将 KeyBinding 应用于 DataGridTemplateColumn。这样做的目的是在Delete按下该列的键时执行命令 - 如果Delete在网格上的其他任何位置按下键,则会执行不同的命令。两个 Delete 命令都存在于网格的 VM 中。
虽然我可以在网格级别定义一个键绑定,然后在命令中测试活动单元格属于哪个列,但这是一个混乱的解决方案,因为:
在多个不同页面上使用网格时无法很好地扩展
有问题的列被定义为 ResourceDictionary 中的资源
此外,我没有看到任何迹象表明这是不可能的……但它却让我无法理解。
我相信我的问题是因为当该单元格成为网格的当前单元格时,焦点不会自动应用于 CellTemplate。单元格上有一个焦点矩形,但单元格内没有触发焦点事件(我已经检查过了)。虽然像 TextBlocks 这样的只读控件可以接收焦点,但如果没有,则无法触发键绑定。键绑定的命令已正确绑定,因此绑定不是问题。
网格定义如下:
<DataGrid x:Name="MyGrid"
ItemsSource="{Binding Path=FilteredSortedData}"
>
<DataGrid.Columns>
<StaticResource ResourceKey="StatusColumn" />
<StaticResource ResourceKey="MySpecialDeleteColumn" />
<StaticResource ResourceKey="...etc..." />
</DataGrid.Columns>
</DataGrid>
然后是专栏:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
x:Class="MyNamespace.GridColumns"
>
<FrameworkElement x:Key="GridColProxy" Name="GridColProxy" DataContext="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, NotifyOnSourceUpdated=True, NotifyOnTargetUpdated=True, Mode=OneWay}" />
<DataGridTemplateColumn x:Key="MySpecialDeleteColumn"
x:Shared="False"
Header="My Special Delete Column"
IsReadOnly="False"
>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel >
<!-- keybinding doesn't work at this level -->
<StackPanel.Style >
<Style TargetType="StackPanel">
<Setter Property="localBehaviours:InputBindingsBehaviour.AttachedKeyBindings">
<Setter.Value>
<localBehaviours:KeyBindingObservable >
<KeyBinding Key="Delete" Command="{Binding Path=DataContext.DeleteItemsCommand, Source={StaticResource GridColProxy}, Mode=OneWay, NotifyOnTargetUpdated=True}" />
</localBehaviours:KeyBindingObservable>
</Setter.Value>
</Setter>
</Style>
</StackPanel.Style>
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
Text="{Binding SomeProperty}"
>
<TextBlock.Style>
<Style TargetType="TextBlock" >
<Style.Triggers>
<DataTrigger Binding="{Binding Path=MySpecialFlag, FallbackValue=false}" Value="True">
<Setter Property="localBehaviours:InputBindingsBehaviour.AttachedKeyBindings">
<Setter.Value>
<localBehaviours:KeyBindingObservable >
<KeyBinding Key="Delete" Command="{Binding Path=DataContext.DeleteItemsCommand, Source={StaticResource GridColProxy}, Mode=OneWay, NotifyOnTargetUpdated=True}" />
</localBehaviours:KeyBindingObservable>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<Image Source="{Binding ...}"
Grid.Column="1"
/>
</Grid>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellStyle>
<Style TargetType="{x:Type DataGridCell}" >
<Style.Triggers>
<!-- placing the keybinding here to apply to the grid cell doesn't have any effect... -->
<DataTrigger Binding="{Binding Path=MySpecialFlag, FallbackValue=false}" Value="True">
<Setter Property="localBehaviours:InputBindingsBehaviour.AttachedKeyBindings">
<Setter.Value>
<localBehaviours:KeyBindingObservable >
<KeyBinding Key="Delete" Command="{Binding Path=DataContext.DeleteItemsCommand, Source={StaticResource GridColProxy}, Mode=OneWay, NotifyOnTargetUpdated=True}" />
</localBehaviours:KeyBindingObservable>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGridTemplateColumn.CellStyle>
</DataGridTemplateColumn>
</ResourceDictionary>
笔记:
忽略
localBehaviours:KeyBindingObservable
,它只是一个附加属性,用于在将键绑定分配给InputBindings
附加控件的属性之前帮助拦截和检查键绑定。这很好用,这里没有问题。我已经展示了我尝试过键绑定的每个地方,它们都没有工作(被触发)。DataTrigger 绑定可以正常工作,因此请忽略它们。
为简洁起见,省略了 CellEditingTemplate
所以我的问题是:
- 如何强制 CellTemplate 项目接收(键盘)焦点,最好使用 XAML?或者有没有办法在单元格级别应用键绑定,以便无论显示的模板如何都能正常工作?
如果 XAML 解决方案不可行,则可以使用 ResourceDictionary 后面代码中的少量事件触发(PreviewKeyDown 等)代码。