Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Styling a Textblock autogenerated in a ContentPresenter

As I saw, a lot of people ran into this exact problem but I can't understand why my case is not working and it is starting to drive me crazy.

Context: I have a DataGrid which is to be colored according to the values of each cell. Hence, I have a dynamic style resolving the actual template to be used for each cell. Backgrounds now work accordingly.

New problem: when I have a dark background, I want the font color to be white and the font weight to be bold so the text is correctly readable. And... I can't style it correctly.

I read some Stackoverflow posts about that:

This one fits my problem but doesn't provide me any working solution This one is also clear and detail but... duh This is almost the same problem as me but... Solution does not work

Here is what I tried so far:

<!-- Green template-->
    <ControlTemplate x:Key="Green" TargetType="{x:Type tk:DataGridCell}">
        <Grid Background="Green">
            <ContentPresenter
                            HorizontalAlignment="Center"
                                      VerticalAlignment="Center">
                <ContentPresenter.Resources>
                    <Style BasedOn="{StaticResource BoldCellStyle}" TargetType="{x:Type TextBlock}" />
                </ContentPresenter.Resources>
            </ContentPresenter>
        </Grid>
    </ControlTemplate>

Does not work. Background is green, but text stays in black & not bold.

BTW, the BoldCellStyle is as easy as it can be:

<Style x:Key="BoldCellStyle" TargetType="{x:Type TextBlock}">
    <Setter Property="FontWeight" Value="Bold"/>
    <Setter Property="Foreground" Value="White" />
</Style>

Okay. Second try (which is a real stupid one but well...)

<!-- Green template  -->
    <ControlTemplate x:Key="Green" TargetType="{x:Type tk:DataGridCell}">
        <Grid Background="Green">
            <ContentPresenter
                            HorizontalAlignment="Center"
                                      VerticalAlignment="Center">
                <ContentPresenter.Resources>
                    <Style x:Key="BoldCellStyle" TargetType="{x:Type TextBlock}">
                        <Setter Property="FontWeight" Value="Bold"/>
                        <Setter Property="Foreground" Value="White" />
                    </Style>

                </ContentPresenter.Resources>
            </ContentPresenter>
        </Grid>
    </ControlTemplate>

Doesn't work either.

Then, I tried to play with the ContentPresenter's properties:

<!-- Green template -->
<ControlTemplate x:Key="Green" TargetType="{x:Type tk:DataGridCell}">
    <Grid Background="Green">
        <ContentPresenter TextElement.FontWeight="Bold" TextElement.Foreground="White" TextBlock.Foreground="White"
                        HorizontalAlignment="Center"
                                  VerticalAlignment="Center" />
    </Grid>
</ControlTemplate>

And... As you can expect, this does not even work.

Intrigued, I used Snoop to browse all the components of my interface. In the first two cases, Snoop actually shows me that each cell is a Grid with a ContentPresenter containing a TextBlock and the actual Style but... The TextBlock's properties do not apply and FontWeight is still normal.

Last case, even more shocking, I can see that snoop shows me that we actually have a ContentPresenter with the right properties (ie TextElement.FontWeight="Bold"), but the autogenerated TextBlock under is - still - not styled.

I can't get what am I missing here. I tried as you can see almost all I could possibly do here, and the TextBlocks keep being non-formatted.

Any idea here? Thanks again!

like image 493
Damascus Avatar asked Nov 04 '22 16:11

Damascus


1 Answers

The DataGridColumns that derive from DataGridBoundColumn (all except DataGridTemplateColumn) has a property ElementStyle that is applied to the TextBlock when it is created. For e.g. DataGridTextColumn It looks like this

static DataGridTextColumn()
{
    ElementStyleProperty.OverrideMetadata(typeof(DataGridTextColumn),
        new FrameworkPropertyMetadata(DefaultElementStyle));
    // ...
}

It overrides the metadata for ElementStyle and provides a new default value, DefaultElementStyle, which basically just sets the default margin for the TextBlock.

public static Style DefaultElementStyle
{
    get
    {
        if (_defaultElementStyle == null)
        {
            Style style = new Style(typeof(TextBlock));
            // Use the same margin used on the TextBox to provide space for the caret
            style.Setters.Add(new Setter(TextBlock.MarginProperty, new Thickness(2.0, 0.0, 2.0, 0.0)));
            style.Seal();
            _defaultElementStyle = style;
        }
        return _defaultElementStyle;
    }
}

This style is set in code everytime a new DataGridCell is created with element.Style = style; and this is overriding the Style you are trying to set, even if you try to set it implicitly.

As far as I know, you'll have to repeat this for your columns

<DataGridTextColumn Header="Column 1" ElementStyle="{StaticResource BoldCellStyle}" .../>
<DataGridTextColumn Header="Column 2" ElementStyle="{StaticResource BoldCellStyle}" .../>
like image 177
Fredrik Hedblad Avatar answered Nov 15 '22 09:11

Fredrik Hedblad