Answered by:
WPF multi-column super header

Question
-
I am trying to accomplish something like what you can see in this image:
http://www.codeproject.com/KB/silverlight/MultipleHeaderSLGrid/FinalResult.PNG
using the WPF datagrid from the codeplex WPFToolkit,
Thanks for any help!!Friday, May 1, 2009 3:44 PM
Answers
-
Okay, as it turns out, it doesn't look like the WPF DataGrid supports SharedSizeGroups. I guess you could still do it by data binding the width of grid columns to DataGrid columns. Something like this:
<Grid> <Grid.RowDefinitions> <RowDefinition Height="auto"/> <RowDefinition Height="2*"/> </Grid.RowDefinitions> <Grid Grid.Row="0"> <Grid.ColumnDefinitions> <ColumnDefinition Width="{Binding ElementName=datagrid1, Path=RowHeaderWidth}" /> <ColumnDefinition Width="{Binding ElementName=Column1, Path=ActualWidth}" /> <ColumnDefinition Width="{Binding ElementName=Column2, Path=ActualWidth}" /> <ColumnDefinition Width="{Binding ElementName=Column3, Path=ActualWidth}" /> <ColumnDefinition Width="{Binding ElementName=Column4, Path=ActualWidth}" /> </Grid.ColumnDefinitions> <Border Grid.Column="1" Grid.ColumnSpan="3" BorderBrush="Black" HorizontalAlignment="Stretch" BorderThickness="2"> <Label>Super Header!!</Label> </Border> </Grid> <tools:DataGrid AutoGenerateColumns="False" Name="datagrid1" Grid.Row="1" RowHeaderWidth="10"> <tools:DataGrid.Columns> <tools:DataGridTextColumn Header="column 1" Width="100" x:Name="Column1" /> <tools:DataGridTextColumn Header="column 2" Width="80" x:Name="Column2"/> <tools:DataGridTextColumn Header="column 3" Width="80" x:Name="Column3"/> <tools:DataGridTextColumn Header="column 4" Width="*" x:Name="Column4"/> </tools:DataGrid.Columns> </tools:DataGrid> </Grid>
In the example you'll see that the "super header" will sit above columns 1,2 and 3 and will resize as you resize those columns. You could easily break it up further by adding more rows to the grid so you can have, for example, one header covering three columns, then another header under it covering only 2 columns. You could also mess about with styles to make it look more like a natural part of the DataGrid.
Also, for some wierd reason, it doesn't work if I don't explicitly set the RowHeaderWidth. Without it, all the columns in the grid will be off by the width of the RowHeader.- Marked as answer by aesl23 Friday, May 1, 2009 8:19 PM
Friday, May 1, 2009 5:16 PM
All replies
-
I don't think you can have a column header in the DataGrid span multiple cells like that, however, I'm thinking that what you could probably do is put your DataGrid within a Grid and use SharedSizeGroups to have the Grid column widths match the DataGrid column widths and then use ColumnSpan in the Grid to add those multi-column headers.Friday, May 1, 2009 3:54 PM
-
Wjousts,
Thanks for your reply, do you think you could give me an example? I am not familiar with SharedSizeGroups... (new to WPF)
Thanks!Friday, May 1, 2009 4:03 PM -
Okay, as it turns out, it doesn't look like the WPF DataGrid supports SharedSizeGroups. I guess you could still do it by data binding the width of grid columns to DataGrid columns. Something like this:
<Grid> <Grid.RowDefinitions> <RowDefinition Height="auto"/> <RowDefinition Height="2*"/> </Grid.RowDefinitions> <Grid Grid.Row="0"> <Grid.ColumnDefinitions> <ColumnDefinition Width="{Binding ElementName=datagrid1, Path=RowHeaderWidth}" /> <ColumnDefinition Width="{Binding ElementName=Column1, Path=ActualWidth}" /> <ColumnDefinition Width="{Binding ElementName=Column2, Path=ActualWidth}" /> <ColumnDefinition Width="{Binding ElementName=Column3, Path=ActualWidth}" /> <ColumnDefinition Width="{Binding ElementName=Column4, Path=ActualWidth}" /> </Grid.ColumnDefinitions> <Border Grid.Column="1" Grid.ColumnSpan="3" BorderBrush="Black" HorizontalAlignment="Stretch" BorderThickness="2"> <Label>Super Header!!</Label> </Border> </Grid> <tools:DataGrid AutoGenerateColumns="False" Name="datagrid1" Grid.Row="1" RowHeaderWidth="10"> <tools:DataGrid.Columns> <tools:DataGridTextColumn Header="column 1" Width="100" x:Name="Column1" /> <tools:DataGridTextColumn Header="column 2" Width="80" x:Name="Column2"/> <tools:DataGridTextColumn Header="column 3" Width="80" x:Name="Column3"/> <tools:DataGridTextColumn Header="column 4" Width="*" x:Name="Column4"/> </tools:DataGrid.Columns> </tools:DataGrid> </Grid>
In the example you'll see that the "super header" will sit above columns 1,2 and 3 and will resize as you resize those columns. You could easily break it up further by adding more rows to the grid so you can have, for example, one header covering three columns, then another header under it covering only 2 columns. You could also mess about with styles to make it look more like a natural part of the DataGrid.
Also, for some wierd reason, it doesn't work if I don't explicitly set the RowHeaderWidth. Without it, all the columns in the grid will be off by the width of the RowHeader.- Marked as answer by aesl23 Friday, May 1, 2009 8:19 PM
Friday, May 1, 2009 5:16 PM -
Thank you very much!! worked perfectlyFriday, May 1, 2009 8:38 PM
-
Any ideas on how to achieve this effect when the grid has frozen columns?Wednesday, June 23, 2010 8:28 AM
-
Thank you very much!! worked perfectly
Yes it does....
Unless the width of your DataGrid is larger than your WPF window.
At which point, when you drag your DataGrid's horizontal scrollbar to the right, all the DataGrid columns shift to the left, but this "fake" header row stays in the same place on the screen.
Ah heck !!
Looks like I'm going to have to turn off the horizontal scrollbar in the DataGrid control, and put a horizontal scrollbar on the <Grid> that the <DataGrid> is in instead.
Come on Microsoft, there must be a nicer way to let us have a second header row in our WPF DataGrids !
Tuesday, July 13, 2010 2:44 PM -
This thread is really helpful
Please remember to click “Mark as Answer” on the post that helps you, and to click “Unmark as Answer” if a marked post does not actually answer your question. This will help other members to find the solution easily.Thursday, September 2, 2010 3:43 AM -
Starting with wjoust approch following solution works even if the horizontal scrollbar of the datagrid is visible.
Xaml: note the datagrid's LayoutUpdated event handler
<Grid>
<Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<Border x:Name="Label1" BorderBrush="Black" BorderThickness="1" HorizontalAlignment="Stretch">
<TextBlock Text="Group1">
</Border>
<Border x:Name="Label2" BorderBrush="Black" BorderThickness="1" HorizontalAlignment="Stretch">
<TextBlock Text="Group2">
</Border>
</StackPanel>
< DataGrid Grid.Row="1" AutoGenerateColumns="False" Name="dg"CanUserReoderColumns="False" IsSynchronizedWithCurrentItem="True"
LayoutUpdated="LayoutUpdated"><DataGrid.Columns>
<DataGridTextColumn Header="column 1" Width="100" x:Name="Column1" /> <DataGridTextColumn Header="column 2" Width="80" x:Name="Column2"/> <DataGridTextColumn Header="column 3" Width="80" x:Name="Column3"/> <DataGridTextColumn Header="column 4" Width="*" x:Name="Column4"/> </DataGrid.Columns> </DataGrid> </Grid>
and in code behind:
// the datagrid's scrollviewer private ScrollViewer sv; private void LayoutUpdated(object sender, EventArgs e) { double offset = 0; GetScrollViewer(dg); if (sv != null && sv.ComputedHorizontalScrollBarVisibility == Visibility.Visible) { offset = sv.ContentHorizontalOffset; } double w = Column1.ActualWidth + Column2.ActualWidth - offset; Label1.Width = w < 0 ? 0 : w; double w2 = Column3.ActualWidth + Column4.ActualWidth ; Label2.Width = w2; } private void GetScrollViewer(DependencyObject obj) { if (sv != null) { return; } var tmp = obj as ScrollViewer; if (tmp != null) { if (tmp.Name.Equals("DG_ScrollViewer")) { sv = tmp; } else { // Recursive call for each visual child for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++) { GetScrollViewer(VisualTreeHelper.GetChild(obj, i)); } } } else { // Recursive call for each visual child for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++) { GetScrollViewer(VisualTreeHelper.GetChild(obj, i)); } } }
- Proposed as answer by Veena Khanna Thursday, May 5, 2011 8:58 AM
Tuesday, January 18, 2011 4:12 PM -
Worked for me. ThanksTuesday, July 9, 2013 8:57 PM
-
Hi, I find this thread very informative. Now I would like to achieve that 1 column header would cover both the super header (grid) and the normal data grid columns so it would look like something like below:
Should Column 1 and Column 6 be on a different DataGrid and just style it to look like part of the Super Headers?
Thursday, July 18, 2013 2:21 AM -
you can use this code as reference :
<my:DataGridTemplateColumn Width="140" > <my:DataGridTemplateColumn.HeaderTemplate> <DataTemplate> <Grid> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="25" /> <ColumnDefinition Width="25" /> <ColumnDefinition Width="25" /> <ColumnDefinition Width="25" /> <ColumnDefinition Width="25" /> </Grid.ColumnDefinitions> <TextBox Grid.Row="0" Grid.ColumnSpan="5" Background="Transparent" HorizontalContentAlignment="Center" BorderBrush="Black" BorderThickness="0,0,0,1">PIL Indicators</TextBox> <TextBox Grid.Row="1" Grid.Column="0" BorderBrush="Black" BorderThickness="0,0,1,0" Width="25">PT</TextBox> <TextBox Grid.Row="1" Grid.Column="1" BorderBrush="Black" BorderThickness="0,0,1,0" Width="25">H</TextBox> <TextBox Grid.Row="1" Grid.Column="2" BorderBrush="Black" BorderThickness="0,0,1,0" Width="25">M</TextBox> <TextBox Grid.Row="1" Grid.Column="3" BorderBrush="Black" BorderThickness="0,0,1,0" Width="25">S</TextBox> <TextBox Grid.Row="1" Grid.Column="4" BorderBrush="Black" BorderThickness="0,0,1,0" Width="25">PI</TextBox> </Grid> </DataTemplate> </my:DataGridTemplateColumn.HeaderTemplate> <my:DataGridTemplateColumn.CellTemplate> <DataTemplate> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="25" /> <ColumnDefinition Width="25" /> <ColumnDefinition Width="25" /> <ColumnDefinition Width="25" /> <ColumnDefinition Width="25" /> </Grid.ColumnDefinitions> <TextBox Grid.Column="0" BorderBrush="Black" BorderThickness="0,0,1,0" Width="25">PT</TextBox> <TextBox Grid.Column="1" BorderBrush="Black" BorderThickness="0,0,1,0" Width="25">H</TextBox> <TextBox Grid.Column="2" BorderBrush="Black" BorderThickness="0,0,1,0" Width="25">M</TextBox> <TextBox Grid.Column="3" BorderBrush="Black" BorderThickness="0,0,1,0" Width="25">S</TextBox> <TextBox Grid.Column="4" BorderBrush="Black" BorderThickness="0,0,1,0" Width="25">PI</TextBox> </Grid> </DataTemplate> </my:DataGridTemplateColumn.CellTemplate> </my:DataGridTemplateColumn>
Tuesday, July 15, 2014 6:56 AM -
I have around 40 datagriviewtextcolums in my datagridview. For some of them Ihave bound their visibility. How would the following code will change to accomodate your changes?
double w = Column1.ActualWidth + Column2.ActualWidth - offset; Label1.Width = w < 0 ? 0 : w; double w2 = Column3.ActualWidth + Column4.ActualWidth ; Label2.Width = w2;
Wednesday, May 6, 2015 9:30 AM -
I have around 40 datagriviewtextcolums in my datagridview. For some of them Ihave bound their visibility. How would the following code will change to accomodate your changes?
double w = Column1.ActualWidth + Column2.ActualWidth - offset; Label1.Width = w < 0 ? 0 : w; double w2 = Column3.ActualWidth + Column4.ActualWidth ; Label2.Width = w2;
DataGridView is not a wpf control, are you definitely using wpf?
The way I do this sort of thing is to build the columns from templates:
http://social.technet.microsoft.com/wiki/contents/articles/28797.aspx#Awkward_Bindings_Data
Wednesday, May 6, 2015 11:18 AM