Горизонтальный DataGrid WPF

Я хотел бы иметь WPF DataGrid с горизонтальной ориентацией, кто-нибудь знает решение?


person eriksmith200    schedule 09.11.2010    source источник


Ответы (5)


Я сделал это ранее, так как мы хотели иметь возможность использовать один и тот же элемент управления для DataGrid и PropertyGrid. Многое нужно изменить (например, выравнивание, прокрутку, расположение стрелок сортировки и т. д.). Существует много кода, чтобы опубликовать все решение, но это должно помочь вам начать. Это пример с автоматически сгенерированными текстовыми столбцами, но вы можете легко изменить его, чтобы использовать другие типы столбцов.

альтернативный текст

<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>

И когда столбцы сгенерированы, мы меняем их положение и поворачиваем текстовые блоки и текстовые поля (это лучше, чем поворот DataGridCell с точки зрения выравнивания, размытия и т. д.).

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);
    }
}
person Fredrik Hedblad    schedule 09.11.2010
comment
Спасибо! Это работает довольно хорошо, горизонтальная полоса прокрутки, когда она включена, появляется вверху (чего и следовало ожидать), а поведение изменения размера заголовка странное (тоже ожидаемо), но для меня это хорошая отправная точка. Есть ли шанс, что вы опубликуете все свое решение? Был бы очень признателен ;) - person eriksmith200; 09.11.2010
comment
Извините, я не могу. Он встроен в решение, которым владеет моя предыдущая компания. Я могу помочь вам в деталях, если вы зададите вопросы, но я не могу загрузить все решение. Удачи! - person Fredrik Hedblad; 09.11.2010
comment
Если подумать, некоторая помощь в размещении горизонтальной полосы прокрутки под элементом управления была бы отличной. - person eriksmith200; 09.11.2010
comment
Обновил мой пример. Родительский ScrollViewer обрабатывает прокрутку - person Fredrik Hedblad; 09.11.2010
comment
Смотрите мой ответ ниже для важных улучшений. - person GilShalit; 06.10.2013
comment
Если у кого-то возникла такая же проблема со средством просмотра прокрутки: прокрутка будет обрезать изображения по горизонтали, а не по вертикали"> stackoverflow.com/questions/32877314/ - person Morgane; 29.10.2015

Здесь я действительно стою на плечах гигантов :-), но у меня есть дополнительное улучшение.

@dimaKudr предложил способ преобразования предопределенных столбцов без кода, а @FrankE уточнил порядок столбцов. Я добавляю способ преобразования автоматически сгенерированных столбцов (AutoGenerateColumns="True") с помощью шаблона DataGrid.CellStyle. Итак, полное (и довольно элегантное) решение:

<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>
person GilShalit    schedule 12.06.2011

Я немного упростил предыдущее решение. Не люблю черную магию с дополнительным скроллвьювером, поэтому не пользуюсь. Но вместо этого я использую дополнительное преобразование масштаба.

<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>

В случае предопределенного списка столбцов можно преобразовать содержимое ячеек непосредственно в 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>

Это позволяет вам полностью избежать кода программной части.

person dimaKudr    schedule 10.12.2010

Я нашел этот подход очень полезным, однако я сделал вращение и зеркальное отображение:

TransformGroup transformGroup = new TransformGroup();
transformGroup.Children.Add(new RotateTransform(90));
transformGroup.Children.Add(new MatrixTransform(-1, 0, 0, 1, 0, 0));

или в Xaml:

<!-- we rotate the whole DataGrid by -90 degree and then mirror via y-Axis so that it is docked vertically to the left side-->
<DataGrid.LayoutTransform>
    <TransformGroup>
        <RotateTransform Angle="90"/>
        <MatrixTransform Matrix="-1,0,0,1,0,0"/>
    </TransformGroup>
</DataGrid.LayoutTransform>

Используя зеркальное отображение, у меня есть поле в конце списка столбцов внизу, а не вверху.

person FrankE    schedule 15.12.2010

Вау, отличное решение, спасибо! Это также требует изменения переключателя выбора строки/столбца между кнопками вверх/вниз и влево/вправо. Я попытался охватить это в событиях keydown или keyup DataGrid, но это ведет себя как-то странно, переворачивая выделение вперед и назад. У кого-нибудь есть лучшее решение, чем то, что ниже? Это просто код для смены табуляции влево и табуляции вправо через то, что изначально является строками.

private void c_dataGrid_KeyUp(object sender, KeyEventArgs e)
{
    switch (e.Key)
    {
        case Key.Tab:
            if (Keyboard.IsKeyDown(Key.LeftShift))
            {
                if (c_dataGrid.SelectedIndex > 0)
                {
                    c_dataGrid.SelectedIndex--;
                }
            }
            else
            {
                if (c_dataGrid.SelectedIndex < c_dataGrid.Items.Count - 1)
                {
                    c_dataGrid.SelectedIndex++;
                }
            }
            e.Handled = true;
            break;
        }
    }
}
person benzhi    schedule 20.04.2021
comment
По-видимому, PreviewKeyDown перехватывает: событие для сетки данных"> stackoverflow.com/questions/6820266/ - person benzhi; 20.04.2021