WPF水平数据网格

27
我想要一个水平方向的WPF数据表格,有人知道解决方法吗?
5个回答

21

我之前做过这个,因为我们想要能够在DataGridPropertyGrid中使用同一个控件。需要改变很多东西(如对齐、滚动、排序箭头的位置等)。要贴出整个解决方案的代码太多了,但这应该可以让你开始着手处理。以下是自动生成文本列的示例,但您可以轻松修改它以使用其他列类型。

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>

当生成列时,我们会反转它们的位置并旋转TextBlocks和TextBoxes(这比旋转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);
    }
}

谢谢!它运行得非常好,启用水平滚动条时出现在顶部(这是可以预料的),标题调整行为很奇怪(也是可以预料的),但这对我来说是一个很好的起点。你有没有可能发布你的整个解决方案?非常感激;) - eriksmith200
抱歉,我不能这样做。这是我之前的公司拥有的解决方案中的一部分。如果你有具体问题,我可以帮你解答,但我不能上传整个解决方案。祝你好运! - Fredrik Hedblad
再想一想,能够帮忙将水平滚动条放在控件下面就太好了。 - eriksmith200
更新了我的示例。父级ScrollViewer处理滚动。 - Fredrik Hedblad
请查看我下面的答案,其中包含重要的改进。 - GilShalit
如果有人遇到与ScrollViewer相关的问题,请参考以下链接:http://stackoverflow.com/questions/32877314/datagrid-scrolling-will-crop-images-horizontally-instead-of-vertically - Morgane

21

我在巨人的肩膀上真正站稳了 :-) 但是,我有一个额外的增强。@dimaKudr提出了一种无需编写代码即可转换预定义列的方法,@FrankE则调整了列的顺序。我要添加的是一种使用DataGrid.CellStyle模板自动转换生成的列(AutoGenerateColumns="True")的方法。所以完整且相当优雅的解决方案如下:

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

13

我对之前的解决方案进行了一些简化。我不喜欢使用额外的滚动条黑魔法,因此我没有使用它。但是,我使用了额外的比例变换。

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

这使您完全摆脱了CodeBehind。


2
我发现这种方法非常有用,但我进行了旋转和镜像处理:
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>

通过使用镜像,我将字段放在列列表底部而不是顶部。


0

哇,太棒了,谢谢!这还需要修改行/列选择开关,使其在上/下和左/右按钮之间切换。我尝试在DataGrid的keydown或keyup事件中处理此问题,但它的行为有点奇怪,来回翻转选择。有没有比下面这个更好的解决方案?这只是通过原始行向左和向右进行Shift Tab操作的代码。

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

显然,PreviewKeyDown是拦截事件的关键:https://dev59.com/8VnUa4cB1Zd3GeqPb5Yb - benzhi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接