【问题标题】:Styling DataGridCell correctly正确设置 DataGridCell 样式
【发布时间】:2011-08-18 11:58:24
【问题描述】:

这是继我之前的问题you can find it right there之后的一个问题

所以。现在我为每一列定义了一个DataGrid 和一个特定的ElementStyle(它只是用粗体和白色定义了TextBlocks 内部——稍后会解决这个问题)

所以现在我有两个问题

第一个问题(已解决)

当我碰巧为我的单元格设置了背景时,它会覆盖默认样式,并且当单元格突出显示时背景保持不变。

样式示例:

<!-- Green template for market-related -->
<ControlTemplate x:Key="Green" TargetType="{x:Type tk:DataGridCell}">
    <Grid Background="Green">
        <ContentPresenter
                        HorizontalAlignment="Center"
                                  VerticalAlignment="Center" />
    </Grid>
</ControlTemplate>

我自然会说这是“正常的”,因为我将Grid 的背景设置为绿色。因此,我尝试了这种方式:

<!-- Light green template for sophis-related -->
<ControlTemplate x:Key="LightGreen" TargetType="{x:Type tk:DataGridCell}">
    <Grid Background="LightGreen">
        <Grid.Resources>
            <Style TargetType="{x:Type Grid}">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type tk:DataGridCell}}, 
                                            Converter={StaticResource DebugConverter}}" Value="True">
                        <Setter Property="Grid.Background" Value="#FF3774FF" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Grid.Resources>
        <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
    </Grid>
</ControlTemplate>

这也行不通。如您所见,我放置了一个 DebugConverter,以便检查触发器是否被实际调用,情况确实如此,但是......背景没有改变(并且 Snoop 确认了这一点......)

第三次尝试:

<!-- Light green template for sophis-related -->
<ControlTemplate x:Key="LightGreen" TargetType="{x:Type tk:DataGridCell}">
    <ControlTemplate.Resources>
        <Style TargetType="{x:Type tk:DataGridCell}">
            <Setter Property="Background" Value="LightGreen" />
        </Style>
    </ControlTemplate.Resources>
    <Grid>
        <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
    </Grid>
</ControlTemplate>

并且...不会显示背景(保持透明)

所以我认为我在这里以错误的方式工作,我想知道我应该怎么做才能定义“未选择”模板。 我会说我可能需要定义一个基于“经典”风格的风格,但是,我该怎么做呢?我尝试添加 TemplateBindings 没有成功

** 编辑:解决方案**

正如 H B 在他的回答中所建议的,问题来自 DependencyProperty Precedence,这是解决方案:

<!-- Light green template for sophis-related -->
<ControlTemplate x:Key="LightGreen" TargetType="{x:Type tk:DataGridCell}">
    <Grid>
        <Grid.Resources>
            <Style TargetType="{x:Type Grid}">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type tk:DataGridCell}}, 
                                            Converter={StaticResource DebugConverter}}" Value="True">
                        <Setter Property="Grid.Background" Value="#FF316AC5" />
                    </DataTrigger>
                    <DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type tk:DataGridCell}}, 
                                            Converter={StaticResource DebugConverter}}" Value="False">
                        <Setter Property="Grid.Background" Value="LightGreen" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Grid.Resources>
        <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
    </Grid>
</ControlTemplate>

第二个问题

现在,让我们谈谈Triggers

基本上,我想做的是将特定的Triggers 定义为我的ElementStyle,因此如果单元格的背景是红色或绿色,则字体颜色为白色(这样做的唯一目的是使红色具有更好的可读性和绿色有点暗,深色背景上的黑色字体会导致失败:p)

编辑 好像我不够清楚:以下样式是通过属性DataGridTextColumn.ElementStyle 应用于数据网格的每个项目的样式。这是代码处理:

    void VolatilityDataGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
    {
        DataGridTextColumn column = e.Column as DataGridTextColumn;
        column.ElementStyle = s_boldCellStyle;
        // Other stuff here...
    }

这是我的工作:

<!-- Cell style for colored matrix-->
<Style x:Key="BoldCellStyle" TargetType="{x:Type TextBlock}">
    <Style.Triggers>
        <DataTrigger Binding="{Binding Background, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type tk:DataGridCell}}}" 
                     Value="Red">
            <Setter Property="Foreground" Value="White" />
        </DataTrigger>
        <DataTrigger Binding="{Binding Background, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type tk:DataGridCell}}, 
                                Converter={StaticResource DebugConverter}}"
                     Value="Green">
            <Setter Property="Foreground" Value="White" />
        </DataTrigger>
    </Style.Triggers>
    <Setter Property="FontWeight" Value="Bold"/>
</Style>

而且...它不起作用。奇怪的是,通过转换器的只是透明的背景颜色。我肯定在这里遗漏了一些东西! 顺便说一句,我也尝试了经典触发器,也没有成功,我在这里使用DataTriggers,这样我就可以调试绑定值了!

现在我已经被困在这个问题上超过三天了,我开始吓坏了……希望 Stackoverflow 社区能救我 :)

谢谢!

编辑

好的,更新。 我明白为什么我的Trigger 不起作用。实际设置的背景位于Grid 上,而不是DataGridCell 上。因此,我没有在那里设置任何颜色是正常的。

但是,我进行了一些测试,发现当绑定设置时,TextBlock 还没有任何父级(Parent = null)。绑定到 Grid 类型的 RelativeSource 会将我绑定到...整个 DataGrid 项目演示者。 我不确定现在该做什么,因为从实际的TextBlock 样式看来,我无法到达父Grid,因此无法根据背景解决我应该显示什么颜色。 另外,我无法更改我的ControlTemplate 中的字体颜色,因为DataGrid 想要每列都有一个Style,默认情况下会覆盖模板的样式(see my previous question and its answer) 所以……我又卡住了!

【问题讨论】:

    标签: wpf datagrid styles controltemplate


    【解决方案1】:

    Dependency Property Value Precedence

    这个:

    <Grid Background="LightGreen">
        <Grid.Resources>
            <Style TargetType="{x:Type Grid}">
                <!-- Trigger Stuff -->
            </Style>
        </Grid.Resources>
        <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
    </Grid>
    

    需要:

    <Grid>
        <Grid.Resources>
            <Style TargetType="{x:Type Grid}">
                <Setter Property="Background" Value="LightGreen"/>
                <!-- Trigger Stuff -->
            </Style>
        </Grid.Resources>
        <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
    </Grid>
    

    目前还不确定您的第二个问题,可能是一个相关问题,我建议为初学者设置TextElement.Foreground 而不是Foreground。将Transparent 作为值并不是很有帮助,您对DataGridCell 使用什么控制模板?如果是自定义的,Background 是否通过 TemplateBinding 正确连接?

    只要使用了Background 属性,它就可以工作,所以如果你有一个ControlTemplate 在内部设置东西,你需要将它外部化。一个普通的DataGrid 例子:

    <DataGrid.CellStyle>
        <Style TargetType="{x:Type DataGridCell}">
            <Setter Property="Background" Value="LightGreen"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding Content}" Value="Apple">
                    <Setter Property="Background" Value="Red"/>
                </DataTrigger>
                <DataTrigger Binding="{Binding Content}" Value="Tomato">
                    <Setter Property="Background" Value="Green"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </DataGrid.CellStyle>
    
    <Style TargetType="TextBlock">
        <Style.Triggers>
            <DataTrigger Binding="{Binding Background, RelativeSource={RelativeSource AncestorType={x:Type DataGridCell}}}" Value="Red">
                <Setter Property="Foreground" Value="White"/>
            </DataTrigger>
            <DataTrigger Binding="{Binding Background, RelativeSource={RelativeSource AncestorType={x:Type DataGridCell}}}" Value="Green">
                <Setter Property="Foreground" Value="White"/>
            </DataTrigger>
        </Style.Triggers>
        <Setter Property="FontWeight" Value="Bold"/>
    </Style>
    

    因此,如果CellStyle 设置ControlTemplate,则需要通过 TemplateBinding 连接属性。例如

    <DataGrid.CellStyle>
        <Style TargetType="{x:Type DataGridCell}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type DataGridCell}">
                        <Grid Background="{TemplateBinding Background}">
                            <ContentPresenter />
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
            <Setter Property="Background" Value="LightGreen"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding Content}" Value="Apple">
                    <Setter Property="Background" Value="Red"/>
                </DataTrigger>
                <DataTrigger Binding="{Binding Content}" Value="Tomato">
                    <Setter Property="Background" Value="Green"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </DataGrid.CellStyle>
    

    不要在模板内触发,否则会很乱。

    【讨论】:

    • 感谢您提供有用的链接!感谢您解决了第一个问题:) 关于第二个问题,它是为TextBlocks 定义的样式,所以我真的应该使用TextElement.Foreground 吗?我正在编辑这个问题,因为我发现了可能的原因——这可能会带来一个更棘手的新问题:/
    • @Damascus:起初没有父母的事实不应该有那么大的问题。我仍然不知道在哪里您使用该样式以及它如何与其他组件交互,但您的问题需要更多关于此的上下文。
    • 糟糕,抱歉,刚刚更新了问题,样式被用作DataGridTextColumn.ElementStyle,看看这个:)
    • 知道了!你是完全正确的,外化是解决方案。非常感谢!
    猜你喜欢
    • 1970-01-01
    • 2014-06-13
    • 2014-09-24
    • 1970-01-01
    • 1970-01-01
    • 2014-02-27
    • 2014-02-22
    • 2020-06-21
    相关资源
    最近更新 更多