WPF Toolkit DataGrid: how to get ColumnHeader width to be the same as GridColumn width
For my WPF Toolkit DataGrid I use the following custom column header style:
<Style x:Name="ColumnStyle" x:Key="ColumnHeaderStyle" TargetType="my:DataGridColumnHeader">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Vertical" HorizontalAlignment="Stretch" Background="LightYellow">
<TextBlock Text="{Binding Name}" HorizontalAlignment="Stretch" TextAlignment="Left" Background="LightGreen" />
<TextBlock Text="{Binding Data}" HorizontalAlignment="Stretch" TextAlignment="Right" Background="LightBlue" />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
The header's DataContext is set in code and the Name and Data string properties are displayed correctly using the initial width of the DataGrid like this:
---------------
|Name |
| Data|
---------------
However, when I resize the column, the header display does not reflow, but instead remains the same:
--------------------
|Name |
| Data |
--------------------
where as I expected it to looks like this:
--------------------
|Name |
| Data|
--------------------
What do I need to do to get the desired behavior above?
Similarly, the header content doesn't seem to stretch in the vertical direction either.
Update: Adding
<Setter Property="VerticalAlignment">
<Setter.Value>Bottom</Setter.Value>
</Setter>
to the Style seems to properly align the header to the bottom. Unfortunately, setting the HorizontalAlignment property in the fashion to 'Stretch' doesn't seem to do what I am looking for.
Details for Repro: Below are code snippets that demonstrate the behavior.
Window1.xaml:
<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>
<Style x:Name="ColumnStyle" x:Key="ColumnHeaderStyle" TargetType="my:DataGridColumnHeader">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<DockPanel>
<TextBlock DockPanel.Dock="开发者_开发百科Left" Text="{Binding Name}" />
<TextBlock DockPanel.Dock="Right" Text="{Binding Data}" />
</DockPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
<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>
</Window.Resources>
<Grid>
<my:DataGrid Name="dg"
ColumnHeaderStyle="{StaticResource ColumnHeaderStyle}"
RowHeaderStyle="{StaticResource RowHeaderStyle}"
HeadersVisibility="All">
</my:DataGrid>
</Grid>
</Window>
and the code-behind in Window1.xaml.cs
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Data;
using Microsoft.Windows.Controls;
using SLModel;
namespace GridTest
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(Window1_Loaded);
}
void Window1_Loaded(object sender, RoutedEventArgs e)
{
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" };
Input i3 = new Input() { Name = "I 3", Data = "data 3" };
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" };
Relationship r5 = new Relationship() { Formula = "F5" };
Relationship r6 = new Relationship() { Formula = "F6" };
i1.Relationships.Add(r1);
i1.Relationships.Add(r2);
i2.Relationships.Add(r3);
i2.Relationships.Add(r4);
i3.Relationships.Add(r5);
i3.Relationships.Add(r6);
CreateColumn(o1, 0);
CreateColumn(o2, 1);
CreateColumn(o3, 2);
dg.Items.Add(i1);
dg.Items.Add(i2);
dg.Items.Add(i3);
dg.ColumnWidth = DataGridLength.SizeToHeader;
}
private void CreateColumn(Output output, int index)
{
Binding textBinding = new Binding();
textBinding.Path = new PropertyPath(string.Format("Relationships[{0}].Formula", index));
textBinding.Mode = BindingMode.TwoWay;
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; }
}
}
With simple classes Input, Output, and Relationship as such:
public class Input { public Input() { Relationships = new ObservableCollection(); }
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; } }
Repro steps:
Launch application
Observe column headers 'O 1data 1', 'O 2data 2', and 'O 3data 3'
Make first column wider by dragging the column separator to the right
Observe that the distance between the 'Name' TextBlock (in this case 'O 1') and the 'Data' TextBlock ('data 1') is not changing, i.e., the 'Data' TextBlock is not 'docked' to the right edge of the column header.
I suggest replacing your StackPanel
with a Grid
:
<Style x:Name="ColumnStyle" x:Key="ColumnHeaderStyle" TargetType="my:DataGridColumnHeader">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="{Binding Name}" Background="LightGreen" />
<TextBlock Grid.Row="1" Grid.Column="2" Text="{Binding Data}" Background="LightBlue" />
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
If that doesn't work, you may need to edit the ControlTemplate
for the DataGridColumnHeader
. I'm not sure what the default template looks like, but if the ContentPresenter
is not located inside a stretchable container (like a Grid
), it won't matter if you stretch what's inside the ContentPresenter
, it won't stretch. But one thing I'm pretty sure of, StackPanels
don't stretch even if you tell them to, so definitely try a Grid
in your DataTemplate
first.
Update (fixed)
Okay, I dug up the default ControlTemplate
for DataGridColumnHeader
. It turns out is does use a Grid
, so I don't think that is the problem.
The key might be the ContentPresenter
:
<ContentPresenter
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" />
You might just need to set HorizontalContentAlignment="Stretch"
on your DataGridColumnHeader
style.
Using WPF 4 DataGrid but had this same problem and simply setting HorizontalContentAlignment in the DataGridColumnHeader style solved it for me (credit to DanM who suggested it above)...
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
Use a dock panel instead
<DockPanel Background="LightYellow">
<TextBlock DockPanel.Dock="Left" Text="{Binding Name}" TextAlignment="Left" Background="LightGreen" />
<TextBlock DockPanel.Dock="Right" Text="{Binding Data}" HorizontalAlignment="Right" TextAlignment="Right" Background="LightBlue" />
</DockPanel >
精彩评论