You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF标准DataGrid动态创建大量列时UI卡顿问题求助

WPF标准DataGrid大量列创建卡顿问题解决方案

问题背景

从Xceed DataGrid迁移至WPF标准DataGrid时,遇到列虚拟化相关的UI卡顿问题:动态创建10000列时应用冻结数秒,但分配数据或创建10000行均无延迟。已配置所有虚拟化相关属性(EnableColumnVirtualization="True"、VirtualizingPanel系列属性等),并尝试过ListCollectionView、CollectionViewSource、DataTable等数据源,问题仍存在。

核心原因

WPF标准DataGrid的EnableColumnVirtualization是列显示阶段的虚拟化,仅控制可见区域外的列不渲染;而手动循环添加10000个DataGridColumn对象到Columns集合时,每个列的初始化、集合变更通知都会触发UI线程的同步操作,大量累积导致UI冻结。Xceed DataGrid在列创建的底层机制上做了批量优化或延迟初始化,因此无此问题。

解决方案

关键优化:利用自动列生成替代手动添加

通过AutoGenerateColumns="True"让DataGrid自动从数据源生成列,此方式会结合EnableColumnVirtualization的机制,内部优化列的创建与加载流程,避免手动添加带来的UI线程阻塞。

具体修改步骤

  1. 在XAML中为DataGrid开启自动列生成:
    <DataGrid x:Name="SeriesTableDataGrid"  
              AutoGenerateColumns="True"
              VirtualizingPanel.IsVirtualizing="True"
              VirtualizingPanel.IsContainerVirtualizable="True"
              VirtualizingPanel.IsVirtualizingWhenGrouping="True"
              VirtualizingPanel.VirtualizationMode="Standard"
              EnableColumnVirtualization="True"
              EnableRowVirtualization="True"
              Grid.Row="1">
    </DataGrid>
    
  2. 移除手动添加列的逻辑,直接绑定数据源触发自动列生成:
    修改Button_Click事件,无需逐个创建列,直接设置ItemsSource即可自动生成对应列:
    private void Button_Click(object sender, RoutedEventArgs e)
    {
        SeriesTableDataGrid.EnableColumnVirtualization = true;
        // 直接绑定数据源,自动生成列
        SeriesTableDataGrid.ItemsSource = myDataTableColumnWeighted.AsDataView();
    }
    
  3. (可选)自定义列模板
    如果需要自定义列的样式或类型,可通过AutoGeneratingColumn事件拦截并修改列的配置,避免手动创建所有列:
    private void SeriesTableDataGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
    {
        // 自定义列头
        e.Column.Header = $"Custom {e.PropertyName}";
        // 强制设置为文本列(示例)
        if (e.Column is DataGridTextColumn textColumn)
        {
            textColumn.FontSize = 12;
        }
    }
    
    同时在XAML中绑定该事件:
    <DataGrid x:Name="SeriesTableDataGrid"  
              AutoGenerateColumns="True"
              AutoGeneratingColumn="SeriesTableDataGrid_AutoGeneratingColumn"
              ...>
    </DataGrid>
    

修改后的完整代码

MainWindow.xaml

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="40"/>
            <RowDefinition />
        </Grid.RowDefinitions>
        <Button Content="Generate Columns (Auto)" Click="Button_Click" Width="131" HorizontalAlignment="Left"/>
        <Button Content="Assing data to columns" Click="Button_Click2" HorizontalAlignment="Left" Margin="161,0,0,0" Width="149" />
        <Button Content="Assing data to rows" Click="Button_Click3" Width="149" HorizontalAlignment="Left" Margin="357,0,0,0"/>
        <Button Content="Clear Grid" Click="Button_Click4" Width="149" HorizontalAlignment="Left" Margin="621,0,0,0"/>
        <DataGrid x:Name="SeriesTableDataGrid"  
                  AutoGenerateColumns="True"
                  AutoGeneratingColumn="SeriesTableDataGrid_AutoGeneratingColumn"
                  VirtualizingPanel.IsVirtualizing="True"
                  VirtualizingPanel.IsContainerVirtualizable="True"
                  VirtualizingPanel.IsVirtualizingWhenGrouping="True"
                  VirtualizingPanel.VirtualizationMode="Standard"
                  EnableColumnVirtualization="True"
                  EnableRowVirtualization="True"
                  Grid.Row="1">
        </DataGrid>
    </Grid>
</Window>

MainWindow.xaml.cs

namespace WpfApp1
{
    public partial class MainWindow : Window
    {
        DataTable myDataTableColumnWeighted;
        DataTable myDataTableRowWeighted;
        public MainWindow()
        {
            InitializeComponent();
            myDataTableColumnWeighted = new DataTable();
            myDataTableRowWeighted = new DataTable();
            var myItem = new List<string>();
            for (int i = 0; i < 10000; i++)
            {
                myDataTableColumnWeighted.Columns.Add(new DataColumn("Column " + i));
                myItem.Add("entry " + i);
                var myOtherRow = myDataTableRowWeighted.NewRow();
                myDataTableRowWeighted.Rows.Add(myOtherRow);
            }
            var myRow = myDataTableColumnWeighted.NewRow();
            myRow.ItemArray = myItem.ToArray();
            myDataTableColumnWeighted.Rows.Add(myRow);
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            SeriesTableDataGrid.EnableColumnVirtualization = true;
            // 自动生成列,无需手动添加
            SeriesTableDataGrid.ItemsSource = myDataTableColumnWeighted.AsDataView();
        }

        private void Button_Click2(object sender, RoutedEventArgs e)
        {
            SeriesTableDataGrid.ItemsSource = myDataTableColumnWeighted.AsDataView();
        }

        private void Button_Click3(object sender, RoutedEventArgs e)
        {
            SeriesTableDataGrid.ItemsSource = myDataTableRowWeighted.AsDataView();
        }

        private void Button_Click4(object sender, RoutedEventArgs e)
        {
            SeriesTableDataGrid.Columns.Clear();
            SeriesTableDataGrid.ItemsSource = null;
        }

        private void SeriesTableDataGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
        {
            // 自定义列示例:修改列头
            e.Column.Header = $"Col {e.PropertyName.Split(' ')[1]}";
            // 可根据需要设置列的其他属性,如宽度、样式等
            e.Column.Width = DataGridLength.Auto;
        }
    }
}

内容的提问来源于stack exchange,提问作者Madenis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 11:05:21