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

时间:2012-10-03 06:40:33

标签: c# wpf wpfdatagrid

我想知道,当DataGrid或包含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的行为与其他任何控件一样(ListBoxComboBox,{ {1}})。

我可以用触发器实现类似的东西:

ListView

enter image description here

但这个解决方案不完整。首先,它将灰色选定但未聚焦的单元格,甚至网格选择单元为<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> 。第二件事 - 当应用程序窗口失去焦点时,触发器不会触发。

有什么建议吗?

更新

此错误已在.NET 4.5中修复,因此,它不再是实际的。

2 个答案:

答案 0 :(得分: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));

当网格的父窗口变为inactve时,必须更改第二个附加属性:

    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>

有没有更好的解决方案?

答案 1 :(得分: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}"/>