如何“包裹” WPF DataGrid 的列(不是文本/内容)?

发布于 2025-01-14 02:32:14 字数 766 浏览 3 评论 0原文

我正在尝试实现一个可以“包装”WPF DataGrid 的解决方案 - 我的意思是整个列和行都包装,而不是它们的文本或内容(见下图) .

我有一组由列和行(带有列标题)组成的数据,我想在限制窗口的宽度约束时将其换行,而不是使用水平滚动条,这意味着数据会在屏幕外显示。

输入图片此处的描述

我曾尝试过使用 WrapPanel 作为 DataGrid 的 ItemsPanelTemplate,但是我无法在此基础上进一步实现我想要的目标。

    <DataGrid.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel Orientation="Horizontal" />
            </ItemsPanelTemplate>
        </DataGrid.ItemsPanel>

如果有一个答案可以使用另一个控件(即 ListView 或 GridView)实现我想要的目标而不需要妥协,我会很高兴。

我当前的解决方案是手动修改我的 ItemsSource 并将其分解,然后创建多个预定大小的 DataGrid,这不是很灵活。

I'm trying to implement a solution where I can 'wrap' a WPF DataGrid - by that I mean that the entire columns and rows wrap, not their text or content (see image below).

I have a set of data comprised of columns and rows (with column headers) that I want to wrap when constricting the window's width constraints, rather than instead using a horizontal scroll bar which would mean data is presented off-screen.

enter image description here

I had a look at using a WrapPanel as the ItemsPanelTemplate of my DataGrid, however I was not able to build on this further to achieve what I wanted.

    <DataGrid.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel Orientation="Horizontal" />
            </ItemsPanelTemplate>
        </DataGrid.ItemsPanel>

If there is an answer that achieves what I want using another control, i.e. a ListView or GridView without compromises, I would be happy with that.

My current solution is to manually modify my ItemsSource and break that up, and then create multiple DataGrids of a pre-determined size, which is not very flexible.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

羅雙樹 2025-01-21 02:32:14

测试 DataGrid.ItemsPanel 和 WrapPanel

DataGrid 仅显示数据行。因此,如果我们将 WrapPanel.Orientation 设置为“水平”:

<DataGrid x:Name="dg" ItemsSource="{Binding _humans}">
    <DataGrid.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel Orientation="Horizontal"/>
        </ItemsPanelTemplate>
    </DataGrid.ItemsPanel>
</DataGrid>

每行将水平并排放置:
DataGrid 和WrapPanel

ListView 和 GridView

如果我们想单独显示属性列,我们应该为每个属性使用一个 ListView。 GridView 将用于显示标题。在 XAML 文档中,我们为 WrapPanel 设置名称。

<Grid>
    <ScrollViewer VerticalScrollBarVisibility="Auto">
        <WrapPanel Name="wraper" Orientation="Horizontal">
        </WrapPanel>
    </ScrollViewer>
</Grid>

背后的代码实现如下:

public partial class MainWindow : Window
    {
        private IList<Human> _humans;
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            CreateHumans();
            wraper.Children.Add(CreateListViewFor("FirstName"));
            wraper.Children.Add(CreateListViewFor("LastName"));
            wraper.Children.Add(CreateListViewFor("Age"));
            wraper.Children.Add(CreateListViewFor("Bday", "Birthday"));
            wraper.Children.Add(CreateListViewFor("Salary"));
            wraper.Children.Add(CreateListViewFor("Id", "Identification"));
        }

        private void CreateHumans()
        {
            _humans = new List<Human>();
            for (int i = 10; i < 20; i++)
            {
                var human = new Human();
                human.FirstName = "Zacharias";
                human.LastName = "Barnham";
                human.Bday = DateTime.Parse("1.3.1990");
                human.Id = "ID-1234-zxc";
                human.Salary = 2_000_000;
                _humans.Add(human);
            }
        }

        private ListView CreateListViewFor(string propertyName, string header)
        {
            var lv = new ListView();
            var gv = new GridView();
            lv.ItemsSource = _humans;
            lv.View = gv;
            lv.SelectionChanged += UpdateSelectionForAllListViews;
            gv.Columns.Add(new GridViewColumn() { Header = header, DisplayMemberBinding = new Binding(propertyName), Width = 100 });
            return lv;
        }

        private ListView CreateListViewFor(string propertyName)
        {
            return CreateListViewFor(propertyName, propertyName);
        }

        private void UpdateSelectionForAllListViews(object sender, SelectionChangedEventArgs e)
        {
            int index = (sender as ListView).SelectedIndex;
            foreach (var child in wraper.Children)
            {
                (child as ListView).SelectedIndex = index;
            }
        }
    }

我们调用 CreateListViewFor() 方法向 WrapPanel 提供 ListView 对象。我们为 Selection Changed 事件创建回调以更新每个列表的选择。造型由你决定。

下一张 gif 显示了最终结果:
最终结果

Testing DataGrid.ItemsPanel and WrapPanel

The DataGrid only displays rows of data. So, if we set WrapPanel.Orientation to "Horizontal":

<DataGrid x:Name="dg" ItemsSource="{Binding _humans}">
    <DataGrid.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel Orientation="Horizontal"/>
        </ItemsPanelTemplate>
    </DataGrid.ItemsPanel>
</DataGrid>

Each row will be positioned side by side horizontally:
DataGrid and WrapPanel

ListView and GridView

If we want to display Property columns separately, we should use a ListView for each property. The GridView will be used for displaying the header. In the XAML document we set a Name for the WrapPanel.

<Grid>
    <ScrollViewer VerticalScrollBarVisibility="Auto">
        <WrapPanel Name="wraper" Orientation="Horizontal">
        </WrapPanel>
    </ScrollViewer>
</Grid>

The code behind is implemented as:

public partial class MainWindow : Window
    {
        private IList<Human> _humans;
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            CreateHumans();
            wraper.Children.Add(CreateListViewFor("FirstName"));
            wraper.Children.Add(CreateListViewFor("LastName"));
            wraper.Children.Add(CreateListViewFor("Age"));
            wraper.Children.Add(CreateListViewFor("Bday", "Birthday"));
            wraper.Children.Add(CreateListViewFor("Salary"));
            wraper.Children.Add(CreateListViewFor("Id", "Identification"));
        }

        private void CreateHumans()
        {
            _humans = new List<Human>();
            for (int i = 10; i < 20; i++)
            {
                var human = new Human();
                human.FirstName = "Zacharias";
                human.LastName = "Barnham";
                human.Bday = DateTime.Parse("1.3.1990");
                human.Id = "ID-1234-zxc";
                human.Salary = 2_000_000;
                _humans.Add(human);
            }
        }

        private ListView CreateListViewFor(string propertyName, string header)
        {
            var lv = new ListView();
            var gv = new GridView();
            lv.ItemsSource = _humans;
            lv.View = gv;
            lv.SelectionChanged += UpdateSelectionForAllListViews;
            gv.Columns.Add(new GridViewColumn() { Header = header, DisplayMemberBinding = new Binding(propertyName), Width = 100 });
            return lv;
        }

        private ListView CreateListViewFor(string propertyName)
        {
            return CreateListViewFor(propertyName, propertyName);
        }

        private void UpdateSelectionForAllListViews(object sender, SelectionChangedEventArgs e)
        {
            int index = (sender as ListView).SelectedIndex;
            foreach (var child in wraper.Children)
            {
                (child as ListView).SelectedIndex = index;
            }
        }
    }

We call our CreateListViewFor() method to provide ListView objects to the WrapPanel. We create a callback for the Selection Changed event to update the selection for each list. The styling is up to you.

The next gif shows the final result:
Final result

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文