Style all DataGridTextColumns via AttachedProperty
Asked Answered
B

1

2

What I tried to do is create a Style to apply a WordWrap on all DataGridTextColumns in a Datagrid without explicitly setting it like this.

<DataGrid ItemsSource="{Binding Lines}">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Column1" Binding="{Binding Path=Result1}">
            <DataGridTextColumn.ElementStyle>
                <Style TargetType="{x:Type TextBlock}">
                    <Setter Property="TextWrapping" Value="Wrap"/>
                </Style>
            </DataGridTextColumn.ElementStyle>
        </DataGridTextColumn>
    </DataGrid.Columns>
</DataGrid>

Unfortunately it is not possible to use some Style as below directly, because DataGridTextColumn isn't a FrameworkElement.

<Style TargetType="{x:Type TextBlock}" x:Key="WrapText">
    <Setter Property="TextWrapping" Value="Wrap"/>
</Style>

I found this workaround https://mcmap.net/q/385048/-why-can-39-t-i-style-a-datagridtextcolumn by RayBurns and was trying to figure out how it's working. However, I'm new to attached properties and therefore don't understand why it is not working.

The c# code seems to be ok.

public class MyDataGridHelper : DependencyObject
{
    private static readonly DependencyProperty TextColumnStyleProperty = DependencyProperty.RegisterAttached("TextColumnStyle", typeof(Style), typeof(MyDataGridHelper), new PropertyMetadata
    {
        PropertyChangedCallback = (obj, e) =>
        {
            var grid = (DataGrid)obj;
            if (e.OldValue == null && e.NewValue != null)
                grid.Columns.CollectionChanged += (obj2, e2) =>
                {
                    UpdateColumnStyles(grid);
                };
        }
    });

    public static void SetTextColumnStyle(DependencyObject element, Style value)
    {
        element.SetValue(TextColumnStyleProperty, value);
    }
    public static Style GetTextColumnStyle(DependencyObject element)
    {
        return (Style)element.GetValue(TextColumnStyleProperty);
    }

    private static void UpdateColumnStyles(DataGrid grid)
    {
        var style = GetTextColumnStyle(grid);
        foreach (var column in grid.Columns.OfType<DataGridTextColumn>())
            foreach (var setter in style.Setters.OfType<Setter>())
                if (setter.Value is BindingBase)
                    BindingOperations.SetBinding(column, setter.Property, (BindingBase)setter.Value);
                else
                    column.SetValue(setter.Property, setter.Value);
    }
}

I got totally confused is when we get towards figuring out the style setter. Currently I'm trying it this way, which is obviously not working, but actually I don't have a clue what this targettype should really look like.

<local:MyDataGridHelper.TextColumnStyle>
    <Style TargetType="FrameworkElement">
        <Setter Property="TextBlock.TextWrapping" Value="Wrap"/>
    </Style>
</local:MyDataGridHelper.TextColumnStyle>
Boote answered 11/10, 2017 at 13:53 Comment(0)
M
2

You should set the ElementStyle of the columns to the value of the attached property:

public class MyDataGridHelper : DependencyObject
{
    private static readonly DependencyProperty TextColumnStyleProperty = 
        DependencyProperty.RegisterAttached("TextColumnStyle", typeof(Style), typeof(MyDataGridHelper), new PropertyMetadata
    {
        PropertyChangedCallback = (obj, e) =>
        {
            var grid = (DataGrid)obj;
            if (e.OldValue == null && e.NewValue != null)
                grid.Columns.CollectionChanged += (obj2, e2) =>
                {
                    UpdateColumnStyles(grid);
                };
        }
    });

    public static void SetTextColumnStyle(DependencyObject element, Style value)
    {
        element.SetValue(TextColumnStyleProperty, value);
    }
    public static Style GetTextColumnStyle(DependencyObject element)
    {
        return (Style)element.GetValue(TextColumnStyleProperty);
    }

    private static void UpdateColumnStyles(DataGrid grid)
    {
        var style = GetTextColumnStyle(grid);
        foreach (var column in grid.Columns.OfType<DataGridTextColumn>())
            column.ElementStyle = style;
    }
}

Usage:

<DataGrid>
    <local:MyDataGridHelper.TextColumnStyle>
        <Style TargetType="TextBlock">
            <Setter Property="Foreground" Value="Red"/>
            <Setter Property="TextWrapping" Value="Wrap"/>
        </Style>
    </local:MyDataGridHelper.TextColumnStyle>
    ...
</DataGrid>
Maidamaidan answered 11/10, 2017 at 14:32 Comment(1)
One small addition. This will override the whole style of all columns. If there should be some individual information for one column we could do it like this to only add setters. static void UpdateColumnStyles(DataGrid grid) { var origStyle = GetTextColumnStyle(grid); foreach (var column in grid.Columns.OfType<DataGridTextColumn>()) { var newStyle = new Style(); newStyle.BasedOn = column.ElementStyle; newStyle.TargetType = origStyle.TargetType; foreach (var setter in origStyle.Setters.OfType<Setter>()) { newStyle.Setters.Add(setter); } column.ElementStyle = newStyle; } }Boote

© 2022 - 2024 — McMap. All rights reserved.