none
Datagrid Column Width Binding

    Question

  • Hello,

    i build my own custom header above a datagrid. This is needed because of a nested datagrid in one datagridcolumn. Thats why i need a multiline header with bands.

    The header is created with buttons in a grid and gridsplitter between the gridcolumns. In the datagrid i hide the headers with: HeadersVisibility="None".

    Now i want them to synchronize. If i resize the header with the gridsplitter the columnwidth of the datagridcolumn must follow. Also if the content of a cell in the datagrid changes the datagrid columnwidth the header-button shall resize to the datagrid column width.

    This Code is not including the datagrid in the templatecolumn but it shows my problem with synchronization of header button and datagridcolumn:

    I need Binding in <Button Width="xxx" or <ColumnDefinition Width="xxx" and in the <DataGridTextColumn Width="xxx"

    Any ideas how to achieve that synchronization without "codebehind"?

    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="700"
            xmlns:l="clr-namespace:WpfApplication1" WindowState="Maximized">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="25" />
                <RowDefinition Height="200*" />
            </Grid.RowDefinitions>
            <Grid HorizontalAlignment="Stretch" Name="grid1" VerticalAlignment="Stretch">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition x:Name="Col1" Width="30*" />
                    <ColumnDefinition x:Name="Col2" Width="39*" />
                    <ColumnDefinition x:Name="Col3" Width="214*" />
                    <ColumnDefinition x:Name="Col4" Width="164*" />
                    <ColumnDefinition x:Name="Col5" Width="39*" />
                </Grid.ColumnDefinitions>
                <Button Grid.Column="0" Content="Activ" HorizontalAlignment="Stretch" Name="Header_Aktiv" VerticalAlignment="Stretch"  />
                <Button Grid.Column="1" Content="Name" HorizontalAlignment="Stretch" Name="Header_Name" VerticalAlignment="Stretch"  />
                <Button Grid.Column="2" Content="Age" HorizontalAlignment="Stretch" Name="Header_Alter" VerticalAlignment="Stretch"  />
                <Button Grid.Column="3" Content="Type" HorizontalAlignment="Stretch" Name="Header_Typ" VerticalAlignment="Stretch" />
                <GridSplitter Grid.Column="0" HorizontalAlignment="Right" Name="gridSplitter1" VerticalAlignment="Stretch" Width="2" />
                <GridSplitter Grid.Column="1" HorizontalAlignment="Right" Name="gridSplitter2" VerticalAlignment="Stretch" Width="2" />
                <GridSplitter Grid.Column="2" HorizontalAlignment="Right" Name="gridSplitter3" VerticalAlignment="Stretch" Width="2" />
                <GridSplitter Grid.Column="3" HorizontalAlignment="Right" Name="gridSplitter4" VerticalAlignment="Stretch" Width="2" />
                <GridSplitter Grid.Column="4" HorizontalAlignment="Right" Name="gridSplitter5" VerticalAlignment="Stretch" Width="2" />
            </Grid>
            <DataGrid HeadersVisibility="None" AutoGenerateColumns="False" Grid.Row="1" HorizontalAlignment="Stretch" x:Name="dataGrid1" VerticalAlignment="Stretch" ItemsSource="{Binding Personlist}"  SelectionMode="Single" SelectionUnit="CellOrRowHeader" >
    
                <DataGrid.Columns>
                    <DataGridTextColumn Header="Activ" Binding="{Binding Path=Activ, UpdateSourceTrigger=PropertyChanged}" />
                    <DataGridTextColumn Header="Name" Binding="{Binding Path=Name, UpdateSourceTrigger=PropertyChanged}" />
                    <DataGridTextColumn Header="Age" Binding="{Binding Path=Age, UpdateSourceTrigger=PropertyChanged}" />
                    <DataGridTextColumn Header="Type" Binding="{Binding Path=Type, UpdateSourceTrigger=PropertyChanged}" />
                </DataGrid.Columns>
    
            </DataGrid>
            
        </Grid>
    
    </Window>
    

    Wednesday, February 29, 2012 3:01 PM

Answers

  • Well, it seems DataGridColumns do not derive from FrameworkElement.

    DataGridColumns derive from DependencyObject, so simple bindings only in XAML is not possible.

    Friday, March 09, 2012 7:03 AM

All replies

  • Something like:

    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="700"
            xmlns:l="clr-namespace:WpfApplication1" WindowState="Maximized">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="25" />
                <RowDefinition Height="200*" />
            </Grid.RowDefinitions>
            <Grid HorizontalAlignment="Stretch" Name="grid1" VerticalAlignment="Stretch">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition x:Name="Col1" Width="30*" />
                    <ColumnDefinition x:Name="Col2" Width="39*" />
                    <ColumnDefinition x:Name="Col3" Width="214*" />
                    <ColumnDefinition x:Name="Col4" Width="164*" />
                    <ColumnDefinition x:Name="Col5" Width="39*" />
                </Grid.ColumnDefinitions>
                <Button Grid.Column="0" Content="Activ" HorizontalAlignment="Stretch" Name="Header_Aktiv" VerticalAlignment="Stretch"  />
                <Button Grid.Column="1" Content="Name" HorizontalAlignment="Stretch" Name="Header_Name" VerticalAlignment="Stretch"  />
                <Button Grid.Column="2" Content="Age" HorizontalAlignment="Stretch" Name="Header_Alter" VerticalAlignment="Stretch"  />
                <Button Grid.Column="3" Content="Type" HorizontalAlignment="Stretch" Name="Header_Typ" VerticalAlignment="Stretch" />
                <GridSplitter Grid.Column="0" HorizontalAlignment="Right" Name="gridSplitter1" VerticalAlignment="Stretch" Width="2" />
                <GridSplitter Grid.Column="1" HorizontalAlignment="Right" Name="gridSplitter2" VerticalAlignment="Stretch" Width="2" />
                <GridSplitter Grid.Column="2" HorizontalAlignment="Right" Name="gridSplitter3" VerticalAlignment="Stretch" Width="2" />
    
                <GridSplitter Grid.Column="3" HorizontalAlignment="Right" Name="gridSplitter4" VerticalAlignment="Stretch" Width="2" />
                <GridSplitter Grid.Column="4" HorizontalAlignment="Right" Name="gridSplitter5" VerticalAlignment="Stretch" Width="2" />
            </Grid>
            <DataGrid HeadersVisibility="None" AutoGenerateColumns="False" Grid.Row="1" HorizontalAlignment="Stretch" x:Name="dataGrid1" VerticalAlignment="Stretch" ItemsSource="{Binding Personlist}"  SelectionMode="Single" SelectionUnit="CellOrRowHeader" >
    
                <DataGrid.Columns>
                    <DataGridTextColumn Width="{Binding ElementName=Header_Aktiv, Path=ActualWidth}"   Header="Activ" Binding="{Binding Path=Activ, UpdateSourceTrigger=PropertyChanged}" />
                    <DataGridTextColumn Width="{Binding ElementName=Header_Name, Path=ActualWidth}" Header="Name" Binding="{Binding Path=Name, UpdateSourceTrigger=PropertyChanged}" />
                    <DataGridTextColumn Width="{Binding ElementName=Header_Alter, Path=ActualWidth}" Header="Age" Binding="{Binding Path=Age, UpdateSourceTrigger=PropertyChanged}" />
                    <DataGridTextColumn Width="{Binding ElementName=Header_Typ, Path=ActualWidth}" Header="Type" Binding="{Binding Path=Type, UpdateSourceTrigger=PropertyChanged}" />
                </DataGrid.Columns>
    
            </DataGrid>
    
        </Grid>
    
    </Window>

    Wednesday, February 29, 2012 3:33 PM
  • Bound property, shared between Grid columns and DataGridColumn content width.
    Shown below for the first column:

    <Window x:Class="WpfApplication74.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="700"
            xmlns:l="clr-namespace:WpfApplication74" WindowState="Maximized" x:Name="Window">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="25" />
                <RowDefinition Height="200*" />
            </Grid.RowDefinitions>
            <Grid HorizontalAlignment="Stretch" Name="grid1" VerticalAlignment="Stretch">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition x:Name="Col1" Width="{Binding Col1Width, ElementName=Window}" />
                    <ColumnDefinition x:Name="Col2" Width="39*" />
                    <ColumnDefinition x:Name="Col3" Width="214*" />
                    <ColumnDefinition x:Name="Col4" Width="164*" />
                    <ColumnDefinition x:Name="Col5" Width="39*" />
                </Grid.ColumnDefinitions>
                <Button Grid.Column="0" Content="Activ" HorizontalAlignment="Stretch" Name="Header_Aktiv" VerticalAlignment="Stretch"  />
                <Button Grid.Column="1" Content="Name" HorizontalAlignment="Stretch" Name="Header_Name" VerticalAlignment="Stretch"  />
                <Button Grid.Column="2" Content="Age" HorizontalAlignment="Stretch" Name="Header_Alter" VerticalAlignment="Stretch"  />
                <Button Grid.Column="3" Content="Type" HorizontalAlignment="Stretch" Name="Header_Typ" VerticalAlignment="Stretch" />
                <GridSplitter Grid.Column="0" HorizontalAlignment="Right" Name="gridSplitter1" VerticalAlignment="Stretch" Width="2" />
                <GridSplitter Grid.Column="1" HorizontalAlignment="Right" Name="gridSplitter2" VerticalAlignment="Stretch" Width="2" />
                <GridSplitter Grid.Column="2" HorizontalAlignment="Right" Name="gridSplitter3" VerticalAlignment="Stretch" Width="2" />
                <GridSplitter Grid.Column="3" HorizontalAlignment="Right" Name="gridSplitter4" VerticalAlignment="Stretch" Width="2" />
                <GridSplitter Grid.Column="4" HorizontalAlignment="Right" Name="gridSplitter5" VerticalAlignment="Stretch" Width="2" />
            </Grid>
            <DataGrid HeadersVisibility="None" AutoGenerateColumns="False" Grid.Row="1" HorizontalAlignment="Stretch" x:Name="dataGrid1" VerticalAlignment="Stretch" ItemsSource="{Binding Personlist}"  SelectionMode="Single" SelectionUnit="CellOrRowHeader" >
                <DataGrid.Columns>
                	<DataGridTemplateColumn >
                		<DataGridTemplateColumn.CellTemplate>
                			<DataTemplate>
                				<TextBlock Width="{Binding DataContext.Col1Width, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid}}" Text="{Binding Activ}"/>      			
    						</DataTemplate>       		
    					</DataGridTemplateColumn.CellTemplate>        	
    				</DataGridTemplateColumn>
                    <DataGridTextColumn Header="Name" Binding="{Binding Path=Name, UpdateSourceTrigger=PropertyChanged}" />
                    <DataGridTextColumn Header="Age" Binding="{Binding Path=Age, UpdateSourceTrigger=PropertyChanged}" />
                    <DataGridTextColumn Header="Type" Binding="{Binding Path=Type, UpdateSourceTrigger=PropertyChanged}" />
                </DataGrid.Columns>
            </DataGrid>
        </Grid>
    
    </Window>

    using System.Windows;
    using System.Collections.Generic;
    
    namespace WpfApplication74
    {
        public class Obj
        {
            public string Activ { get; set; }
            public string Name { get; set; }
            public string Age { get; set; }
            public string Type { get; set; }
        }
       
        public partial class MainWindow : Window
        {
            public double Col1Width { get; set; }
            
            public MainWindow()
            {
                Col1Width = 100;
    
                InitializeComponent();
    
                dataGrid1.ItemsSource = new List<Obj> { new Obj { Activ = "True", Age = "41", Name = "Pete", Type = "bloke" } };
    
                DataContext = this;
            }
        }
    }

      

    Can be made two way, by implementing INotifyPropertyChanged.

       

    Regards,
    Pete


    #PEJL

    Wednesday, February 29, 2012 5:16 PM
  • Ok, for two way binding i create a class and implement INotifyPropertyChanged.

    public class HeaderSize : INotifyPropertyChanged
        {
    
            public event PropertyChangedEventHandler PropertyChanged;
    
            public HeaderSize()
            {
                _Col1Width = 100;
            }
    
            private double _Col1Width;
    
            public double Col1Width
            {
                get
                {
                    return _Col1Width;
                }
                set
                {
                    _Col1Width = value;
                    OnPropertyChanged("Col1Width");
                }
    
            }
    
            protected void OnPropertyChanged(string name)
            {
                PropertyChangedEventHandler handler = PropertyChanged;
                if (handler != null)
                {
                    handler(this, new PropertyChangedEventArgs(name));
                }
            }
    
        }

    Then i assign it to my DataContext. The data of the dataGrid where assigned by ItemsSource

    public HeaderSize HS;
    
            public MainWindow()
            {
                InitializeComponent();
    
                HS = new HeaderSize();
    
                dataGrid1.ItemsSource = new List<Obj> { new Obj { Activ = "True", Age = "41", Name = "Pete", Type = "bloke" } };
                this.DataContext = HS;
            }

    Now in the XAML i make the Binding

    <TextBlock Width="{Binding DataContext.Col1Width, Mode=TwoWay}" Text="{Binding Activ}"/>
    <ColumnDefinition x:Name="Col1" Width="{Binding Col1Width, Mode=TwoWay}" />

    But they don't synchronize. Any idea ?

    Regards

    John


    Thursday, March 01, 2012 8:45 AM
  • My approach is based on a live form and doesn't involve any extra properties.

    Thursday, March 01, 2012 11:56 AM
  • I tried your approach but binding the column like this has no effect.

    Width="{Binding ElementName=Header_Aktiv, Path=ActualWidth}"

    When i set this binding to a Button Control, the width is synchronizing but not with the width of the column in the datagrid

    Thursday, March 01, 2012 12:24 PM
  • Well that's strange.

    The code I adapted is binding gridviewcolumn widths ( actually a treelistview but essentially a listview) to a datagrid above.

    These show two collections of the same type. 

    When you adjust the width of one column the other table of data adjusts to match.

    That works.

    So I set some data up, confident this was just going to work.

    It doesn't.

    Might have thought button actualwidth would be much the same.... but apparently not.

    Quite surprising, to put it mildly.

    Thursday, March 01, 2012 4:54 PM
  • It will synchronize with the following code behind:

    PropertyDescriptor pd1 = DependencyPropertyDescriptor.FromProperty(ColumnDefinition.WidthProperty, typeof(ColumnDefinition));
                pd1.AddValueChanged(Col1, new EventHandler(Col1WidthPropertyChanged));
            private void Col1WidthPropertyChanged(object sender, EventArgs e)
            {
                ColAktiv.Width = ((ColumnDefinition)sender).ActualWidth;
            }
    But i hope that there is a soultion with simple bindings.

    Monday, March 05, 2012 10:56 AM
  • Well, it seems DataGridColumns do not derive from FrameworkElement.

    DataGridColumns derive from DependencyObject, so simple bindings only in XAML is not possible.

    Friday, March 09, 2012 7:03 AM
  • Listview no good to you?

    Friday, March 09, 2012 11:11 AM
  • No, i need to edit the data in the grid.
    Saturday, March 10, 2012 2:57 PM
  • You  can make listview editable.  Rarely the best choice nowadays though.
    Sunday, March 11, 2012 8:48 PM
  • What i need to achieve is a table (grid) like this sample:

    (Multiline Header, Cellmerge Header and a Nested Grid in the column "Overview school subjects").

    Well the NestedGrid in the DataGridTemplateColumn is no problem. But the sizable header i only achieved with the DependencyPropertyDescriptor and Code Behind.


    Monday, March 12, 2012 6:33 AM