Search code examples
wpfdatagridheaderresizetoolkit

WPF DataGrid: ColumnHeaderStyle ContentTemplate is not shown in full height until after resizing


This might be a bug in the WPF Toolkit DataGrid.

In my Windows.Resources I define the following ColumnHeaderStyle:

<Style x:Name="ColumnStyle" x:Key="ColumnHeaderStyle" TargetType="my:DataGridColumnHeader">
    <Setter Property="ContentTemplate">
        <Setter.Value>
            <DataTemplate>
                <StackPanel Orientation="Vertical">
                    <TextBlock Text="{Binding Name}" />
                    <TextBlock Text="{Binding Data}" />
                </StackPanel>
            </DataTemplate>
        </Setter.Value>
    </Setter>
</Style>

Because my columns are generated dynamically, I am defining the columns in code:

private void CreateColumn(Output output, int index)
{
    Binding textBinding = new Binding(string.Format("Relationships[{0}].Formula", index));
    DataGridTextColumn tc = new DataGridTextColumn();
    tc.Binding = textBinding;
    dg.Columns.Add(tc);
    tc.Header = output;
}

where Output is a simple class with Name and Data (string) properties.

What I observe is that only the Name property (first TextBlock control in the ContentTemplate's StackPanel) is shown. When I drag one of these column headers, I see the entire header (including the Data TextBlock). Only after manually resizing one of the columns are the column headers rendered correctly. Is there a way to get the column headers to show up correctly in code?

Update: as requested, here is the rest of my code for the repro.

public class Input
{
    public Input() 
    {
        Relationships = new ObservableCollection<Relationship>();
    }

    public string Name { get; set; }
    public string Data { get; set; }

    public ObservableCollection<Relationship> Relationships { get; set; }
}

public class Output
{
    public Output() { }

    public string Name { get; set; }
    public string Data { get; set; }
}

public class Relationship
{
    public Relationship() { }

    public string Formula { get; set; }
}

Here is the XAML markup:

<Window x:Class="GridTest.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300" xmlns:my="http://schemas.microsoft.com/wpf/2008/toolkit">
    <Window.Resources>
        <SolidColorBrush x:Key="RowHeaderIsMouseOverBrush" Color="Red" />
        <SolidColorBrush x:Key="RowBackgroundSelectedBrush" Color="Yellow" />
        <BooleanToVisibilityConverter x:Key="bool2VisibilityConverter" />

        <Style x:Key="RowHeaderGripperStyle" TargetType="{x:Type Thumb}">
            <Setter Property="Height" Value="2"/>
            <Setter Property="Background" Value="Green"/>
            <Setter Property="Cursor" Value="SizeNS"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Thumb}">
                        <Border Padding="{TemplateBinding Padding}"
                Background="{TemplateBinding Background}"/>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

        <Style x:Name="ColumnStyle" x:Key="ColumnHeaderStyle" TargetType="my:DataGridColumnHeader">
            <Setter Property="ContentTemplate">
                <Setter.Value>
                    <DataTemplate>
                        <StackPanel Orientation="Vertical">
                            <TextBlock Text="{Binding Name}" />
                            <TextBlock Text="{Binding Data}" />
                        </StackPanel>
                    </DataTemplate>
                </Setter.Value>
            </Setter>
        </Style>

        <!-- from http://www.codeplex.com/wpf/WorkItem/View.aspx?WorkItemId=9193 -->
        <Style x:Name="RowHeaderStyle" x:Key="RowHeaderStyle" TargetType="my:DataGridRowHeader">
            <Setter Property="Content" Value="{Binding}" />
            <Setter Property="ContentTemplate">
                <Setter.Value>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <TextBlock Text="{Binding Path=Content.Name, RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type my:DataGridRowHeader}}}" 
                                       VerticalAlignment="Center"/>
                            <TextBlock Padding="5">|</TextBlock>
                            <TextBlock Text="{Binding Path=Content.Data, RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type my:DataGridRowHeader}}}"
                                       VerticalAlignment="Center"/>
                        </StackPanel>
                    </DataTemplate>
                </Setter.Value>
            </Setter>
        </Style>

        <DataTemplate x:Key="CellTemplate">
            <StackPanel>
                <TextBox Text="{Binding Formula, Mode=TwoWay}" />
            </StackPanel>
        </DataTemplate>

        <DataTemplate x:Key="CellEditTemplate">
            <StackPanel>
                <TextBox Text="{Binding Formula, Mode=TwoWay}" />
            </StackPanel>
        </DataTemplate>

    </Window.Resources>
    <Grid>
        <my:DataGrid Name="dg" 
                     ColumnHeaderStyle="{StaticResource ColumnHeaderStyle}"
                     RowHeaderStyle="{StaticResource RowHeaderStyle}"
                     HeadersVisibility="All" />
    </Grid>
</Window>

And finally the code-behind:

/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();
        Inputs = new List<Input>();
        Outputs = new List<Output>();

        Input i1 = new Input() { Name = "I 1", Data = "data 1" };
        Input i2 = new Input() { Name = "I 2", Data = "data 2" };


        Inputs.Add(i1); Inputs.Add(i2);

        Output o1 = new Output() { Name = "O 1", Data = "data 1" };
        Output o2 = new Output() { Name = "O 2", Data = "data 2" };
        Output o3 = new Output() { Name = "O 3", Data = "data 3" };

        Outputs.Add(o1); Outputs.Add(o2); Outputs.Add(o3);

        Relationship r1 = new Relationship() { Formula = "F1" };
        Relationship r2 = new Relationship() { Formula = "F2" };
        Relationship r3 = new Relationship() { Formula = "F3" };
        Relationship r4 = new Relationship() { Formula = "F4" };

        i1.Relationships.Add(r1);
        i1.Relationships.Add(r2);
        i2.Relationships.Add(r3);
        i2.Relationships.Add(r4);


        CreateColumn(o1, 0);
        CreateColumn(o2, 1);
        CreateColumn(o3, 2);

        dg.Items.Add(i1);
        dg.Items.Add(i2);
        dg.ColumnWidth = DataGridLength.SizeToHeader;
    }

    private void CreateColumn(Output output, int index)
    {
        Binding textBinding = new Binding(string.Format("Relationships[{0}].Formula", index));
        DataGridTextColumn tc = new DataGridTextColumn();
        tc.Binding = textBinding;
        dg.Columns.Add(tc);
        tc.Header = output;
    }

    private List<Output> Outputs { get; set; }
    private List<Input> Inputs { get; set; }
}

Solution

  • The issue is fixed if the columns are created in the Loaded event handler, rather than in the constructor of the window.