如何设置自定义DataGrid非活动选择颜色?

5

我在想,有没有办法在DataGrid或包含DataGrid的窗口变得不活跃时设置自定义的选择颜色?

例如,这里是显示相同数据的DataGridListBox。两个控件都有一个选择的项目。最初,DataGrid获得了输入焦点:

enter image description here

一切看起来很好 - ListBox中的选定项是灰色的。然后,让我们将焦点移到ListBox上:

enter image description here

现在,DataGrid的行为是不正确的 - 选择颜色没有改变。
我知道关于SystemColors.HighlightBrushKeySystemColors.ControlBrushKey的事情。这个XAML被放置在窗口的资源中:

    <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="BlueViolet"/>
    <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="DarkGray"/>

看起来 DataGrid 忽略了第二个属性 - SystemColors.ControlBrushKey,而我希望 DataGrid 的表现和其他控件 (ListBox, ComboBox, ListView) 一样。

使用触发器可以实现类似的效果:

<Style TargetType="{x:Type DataGridCell}">
    <Style.Triggers>
        <MultiTrigger>
            <MultiTrigger.Conditions>
                <Condition Property="IsFocused" Value="False"/>
                <Condition Property="IsSelected" Value="True"/>
            </MultiTrigger.Conditions>
            <Setter Property="Background" Value="DarkGray"/>
        </MultiTrigger>
    </Style.Triggers>
</Style>

显示图片描述

但是这个解决方案是不完整的。首先,它会使选定但未聚焦单元格变灰,即使网格选择单元是FullRow。第二件事是,当应用程序窗口失去焦点时,触发器不会触发。

有什么建议吗?

更新

.NET 4.5中已经修复了这个错误,因此不再适用。

2个回答

2
我在 .Net 4.5 中使用 DataGrid.Resources 实现了这种行为。
<DataGrid.Resources>
    <SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}" Color="{x:Static SystemColors.HighlightColor}"/>
    <SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}" Color="{x:Static SystemColors.HighlightTextColor}"/>


这个DataGrid中的错误已在4.5中修复。现在,DataGrid的行为与任何“正常”的Selector一样。 - Dennis

2
我找到了解决方案,但它看起来并不优雅。
基本问题如下:
- `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;

        // IsValid will be false, if there's no focused cell.
        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}}}"/>

接下来,我需要一个单元格样式来设置适当的背景颜色:
        <!-- A style of selected cell in DataGrid, when there's no any focused cells in DataGrid -->
        <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>

有更好的解决方案吗?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接