我找到了解决方案,但它看起来并不优雅。
基本问题如下:
- `DataGrid.IsFocused` 永远是 `false`,因为焦点在具体的单元格上而不在整个表格上。
- 在单元格样式中无法确定表格中是否有任何聚焦的单元格。只能测试当前单元格的 `IsFocused`。
- 数据网格不会对其父窗口的去活动做出响应。
唯一确定数据网格是否拥有焦点的方法是检查 `DataGrid.CurrentCell` 属性。不幸的是,它是一个结构,你不能创建一个触发器来检查此属性是否为 `{x:Null}`。
为了解决这些问题,我需要两个附加属性。第一个旨在确定表格中是否存在任何聚焦的单元格。结果必须是 `bool` 类型,源为 `DataGridCellInfo`。因此,首先必须编写转换器:
[ValueConversion(typeof(DataGridCellInfo), typeof(bool))]
public sealed class DataGridCellInfoToBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null || value.GetType() != typeof(DataGridCellInfo) || targetType != typeof(bool))
return DependencyProperty.UnsetValue;
return ((DataGridCellInfo)value).IsValid;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
附加属性:
public static bool GetHasFocusedCell(DependencyObject obj)
{
return (bool)obj.GetValue(HasFocusedCellProperty);
}
public static void SetHasFocusedCell(DependencyObject obj, bool value)
{
obj.SetValue(HasFocusedCellProperty, value);
}
public static readonly DependencyProperty HasFocusedCellProperty = DependencyProperty.RegisterAttached(
"HasFocusedCell",
typeof(bool),
typeof(FocusedCellBehavior),
new UIPropertyMetadata(false));
当包含表格的父窗口失去焦点时,需要更改第二个附加属性:
public static bool GetIsParentWindowActive(DependencyObject obj)
{
return (bool)obj.GetValue(IsParentWindowActiveProperty);
}
public static void SetIsParentWindowActive(DependencyObject obj, bool value)
{
obj.SetValue(IsParentWindowActiveProperty, value);
}
public static readonly DependencyProperty IsParentWindowActiveProperty = DependencyProperty.RegisterAttached(
"IsParentWindowActive",
typeof(bool),
typeof(FocusedCellBehavior),
new UIPropertyMetadata(false));
现在,让我们在XAML中绑定附加属性:
<!-- A converter to define, is there any focused cell in DataGrid -->
<local:DataGridCellInfoToBooleanConverter x:Key="DataGridCellInfoToBooleanConverter"/>
<DataGrid Grid.Row="0" SelectionUnit="FullRow" SelectionMode="Single"
ItemsSource="{Binding}"
local:FocusedCellBehavior.HasFocusedCell="{Binding CurrentCell, RelativeSource={RelativeSource Mode=Self}, Converter={StaticResource DataGridCellInfoToBooleanConverter}}"
local:FocusedCellBehavior.IsParentWindowActive="{Binding IsActive, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}"/>
接下来,我需要一个单元格样式来设置适当的背景颜色:
<!
<Style TargetType="{x:Type DataGridCell}" x:Key="InactiveSelectedCellStyle">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
</Trigger>
</Style.Triggers>
</Style>
并且使用网格样式来触发触发器,当附加属性更改其值时:
<!
A style of DataGrid, that defines a couple of triggers, which being fired
when helper attached properties will change their values
<Style TargetType="{x:Type DataGrid}">
<Style.Triggers>
<Trigger Property="local:FocusedCellBehavior.IsParentWindowActive" Value="False">
<Setter Property="CellStyle" Value="{StaticResource InactiveSelectedCellStyle}"/>
</Trigger>
<Trigger Property="local:FocusedCellBehavior.HasFocusedCell" Value="False">
<Setter Property="CellStyle" Value="{StaticResource InactiveSelectedCellStyle}"/>
</Trigger>
</Style.Triggers>
</Style>
有更好的解决方案吗?
DataGrid
中的错误已在4.5中修复。现在,DataGrid
的行为与任何“正常”的Selector
一样。 - Dennis