WPF horizontal DataGrid WPF horizontal DataGrid wpf wpf

WPF horizontal DataGrid


I am truly standing on the shoulders of giants here :-) but, I have an additional enhancement.

@dimaKudr suggested a way to transform predefined columns without code behind, and @FrankE refined the order of the columns. What i am adding is a way to transform, automatically generated columns (AutoGenerateColumns="True"), by using the DataGrid.CellStyle template. So the complete (and quite elegant) solution is:

<DataGrid ItemsSource="{Binding YourObservableCollection}"        AutoGenerateColumns="True"        AutoGeneratingColumn="OnAutoGeneratingColumn">    <DataGrid.LayoutTransform>        <TransformGroup>            <RotateTransform Angle="90"/>            <MatrixTransform Matrix="-1,0,0,1,0,0"/>        </TransformGroup>    </DataGrid.LayoutTransform>    <DataGrid.ColumnHeaderStyle>        <Style TargetType="{x:Type DataGridColumnHeader}"                BasedOn="{StaticResource {x:Type DataGridColumnHeader}}">            <Setter Property="LayoutTransform">                <Setter.Value>                    <TransformGroup>                        <RotateTransform Angle="-90"/>                        <ScaleTransform ScaleX="1" ScaleY="-1" />                    </TransformGroup>                </Setter.Value>            </Setter>        </Style>    </DataGrid.ColumnHeaderStyle>    <DataGrid.CellStyle>        <Style  TargetType="DataGridCell">            <Setter Property="LayoutTransform">                <Setter.Value>                    <TransformGroup>                        <RotateTransform Angle="-90"/>                        <ScaleTransform ScaleX="1" ScaleY="-1" />                    </TransformGroup>                </Setter.Value>            </Setter>        </Style>    </DataGrid.CellStyle></DataGrid>


I've done this earlier since we wanted to be able to use the same control for a DataGrid and a PropertyGrid. Alot of things have to be changed (like alignment, scrolling, positioning of sort-arrows etc.). There is way to much code to post the whole solution but this should get you started. This is an example with Autogenerated TextColumns but you can easily modify it to use other column types.

alt text

<ScrollViewer Name="c_dataGridScrollViewer"              Loaded="c_dataGridScrollViewer_Loaded"              VerticalScrollBarVisibility="Auto"              HorizontalScrollBarVisibility="Auto">    <DataGrid x:Name="c_dataGrid"              HorizontalAlignment="Left"              VerticalAlignment="Top"              AutoGeneratedColumns="c_dataGrid_AutoGeneratedColumns"              HorizontalScrollBarVisibility="Hidden"              VerticalScrollBarVisibility="Hidden">        <DataGrid.ColumnHeaderStyle>            <Style TargetType="{x:Type DataGridColumnHeader}">                <Setter Property="LayoutTransform">                    <Setter.Value>                        <TransformGroup>                            <RotateTransform Angle="90"/>                        </TransformGroup>                    </Setter.Value>                </Setter>            </Style>        </DataGrid.ColumnHeaderStyle>        <DataGrid.LayoutTransform>            <TransformGroup>                <RotateTransform Angle="-90"/>            </TransformGroup>        </DataGrid.LayoutTransform>    </DataGrid></ScrollViewer>

And when the Columns are generated, we reverse their positions and rotates the TextBlocks and TextBoxes (This is better than rotating the DataGridCell in terms of alignment, blur etc.)

private void c_dataGridScrollViewer_Loaded(object sender, RoutedEventArgs e){    // Add MouseWheel support for the datagrid scrollviewer.    c_dataGrid.AddHandler(MouseWheelEvent, new RoutedEventHandler(DataGridMouseWheelHorizontal), true);}private void DataGridMouseWheelHorizontal(object sender, RoutedEventArgs e){    MouseWheelEventArgs eargs = (MouseWheelEventArgs)e;    double x = (double)eargs.Delta;    double y = c_dataGridScrollViewer.VerticalOffset;    c_dataGridScrollViewer.ScrollToVerticalOffset(y - x);}private void c_dataGrid_AutoGeneratedColumns(object sender, EventArgs e){    TransformGroup transformGroup = new TransformGroup();    transformGroup.Children.Add(new RotateTransform(90));    foreach (DataGridColumn dataGridColumn in c_dataGrid.Columns)    {        if (dataGridColumn is DataGridTextColumn)        {            DataGridTextColumn dataGridTextColumn = dataGridColumn as DataGridTextColumn;            Style style = new Style(dataGridTextColumn.ElementStyle.TargetType, dataGridTextColumn.ElementStyle.BasedOn);            style.Setters.Add(new Setter(TextBlock.MarginProperty, new Thickness(0, 2, 0, 2)));            style.Setters.Add(new Setter(TextBlock.LayoutTransformProperty, transformGroup));            style.Setters.Add(new Setter(TextBlock.HorizontalAlignmentProperty, HorizontalAlignment.Center));            Style editingStyle = new Style(dataGridTextColumn.EditingElementStyle.TargetType, dataGridTextColumn.EditingElementStyle.BasedOn);            editingStyle.Setters.Add(new Setter(TextBox.MarginProperty, new Thickness(0, 2, 0, 2)));            editingStyle.Setters.Add(new Setter(TextBox.LayoutTransformProperty, transformGroup));            editingStyle.Setters.Add(new Setter(TextBox.HorizontalAlignmentProperty, HorizontalAlignment.Center));            dataGridTextColumn.ElementStyle = style;            dataGridTextColumn.EditingElementStyle = editingStyle;        }    }    List<DataGridColumn> dataGridColumns = new List<DataGridColumn>();    foreach (DataGridColumn dataGridColumn in c_dataGrid.Columns)    {        dataGridColumns.Add(dataGridColumn);    }    c_dataGrid.Columns.Clear();    dataGridColumns.Reverse();    foreach (DataGridColumn dataGridColumn in dataGridColumns)    {        c_dataGrid.Columns.Add(dataGridColumn);    }}


I've simplified a little bit previous solution. I do not like black magic with additional scrollviewer, so I do not use it. But instead I use additional scale transformation.

<DataGrid.LayoutTransform>    <TransformGroup>        <RotateTransform Angle="-90"/>        <ScaleTransform ScaleX="1" ScaleY="-1" />    </TransformGroup></DataGrid.LayoutTransform><DataGrid.ColumnHeaderStyle>    <Style TargetType="{x:Type DataGridColumnHeader}"           BasedOn="{StaticResource {x:Type DataGridColumnHeader}}">        <Setter Property="LayoutTransform">            <Setter.Value>                <TransformGroup>                    <RotateTransform Angle="-90"/>                    <ScaleTransform ScaleX="1" ScaleY="-1" />                </TransformGroup>            </Setter.Value>        </Setter>    </Style></DataGrid.ColumnHeaderStyle>

In case of predefined list of colums it is possible to transfom cells content directly in XAML:

<Style x:Key="TextCellStyle" TargetType="{x:Type TextBlock}">    <Setter Property="LayoutTransform">        <Setter.Value>            <TransformGroup>                <RotateTransform Angle="-90"/>                <ScaleTransform ScaleX="1" ScaleY="-1" />            </TransformGroup>        </Setter.Value>    </Setter></Style>

This allows you completely escape codebehind.