当前位置: 首页 > news >正文

WPF中异步代码更新DataGrid控件卡顿问题分析


问题背景

在 WPF 开发中,我们经常需要动态更改 DataGrid 的列结构和数据源。例如,在报表系统中切换不同的数据视图,或在数据分析工具中展示不同结构的数据集。然而,这个看似简单的操作却隐藏着一个容易被忽视的陷阱。

问题复现

假设我们有以下场景:两个 DataTable,列名完全不同,需要在它们之间切换显示。

初始代码

xaml代码如下:

<Window x:Class="WpfApp1.DataGridFreezeDemoWindow"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"xmlns:local="clr-namespace:WpfApp1"mc:Ignorable="d"Title="DataGridFreezeDemoWindow" Height="450" Width="800"><Grid><Grid.RowDefinitions><RowDefinition Height="*"/><RowDefinition Height="Auto"/></Grid.RowDefinitions><DataGrid x:Name="dg"/><Button x:Name="btnUpdate" Grid.Row="1" Click="UpdateButton_Click" >Update Columns And Rows</Button></Grid>
</Window>

xaml.cs代码如下:

    public DataGridFreezeDemoWindow(){InitializeComponent();_dt = new DataTable();// 向_dt中添加50列;"Column"开头for (int i = 0; i < 50; i++){_dt.Columns.Add($"Column{i}", typeof(string));}// 添加500行随机数据到_dtRandom random = new Random();for (int i = 0; i < 500; i++){DataRow row = _dt.NewRow();for (int j = 0; j < 50; j++){row[j] = $"Row{i}_Col{j}_{random.Next(1000)}";}_dt.Rows.Add(row);}_dt.AcceptChanges();// 使用不同的列名初始化_dt2,"Field"开头_dt2 = new DataTable();for (int i = 0; i < 50; i++){_dt2.Columns.Add($"Field_{i + 1}", typeof(string));}// 向_dt2添加500行随机数据for (int i = 0; i < 500; i++){DataRow row = _dt2.NewRow();for (int j = 0; j < 50; j++){row[j] = $"Data{i}_F{j + 1}_{random.Next(5000, 10000)}";}_dt2.Rows.Add(row);}_dt2.AcceptChanges();// 设定是否使用的第一个datatable_useFirstDataTable = false;
        ApplyDataGridColumns(_dt);dg.ItemsSource = _dt.DefaultView;}private DataTable _dt;private DataTable _dt2;private bool _useFirstDataTable = true;
   private void ApplyDataGridColumns(DataTable dataTable){// Disable auto-generated columnsdg.AutoGenerateColumns = false;// Clear existing columns
       dg.Columns.Clear();// Manually create columns for the DataTablefor (int i = 0; i < dataTable.Columns.Count; i++){DataGridTextColumn column = new DataGridTextColumn{Header = dataTable.Columns[i].ColumnName,Binding = new Binding($"[{i}]"),IsReadOnly = true};dg.Columns.Add(column);}}

 

初看之下,切换逻辑很简单

private async void UpdateButton_Click(object sender, RoutedEventArgs e)    
btnUpdate.IsEnabled = false;

try{DataTable currentDataTable = _useFirstDataTable ? _dt : _dt2;// 更新列定义 ApplyDataGridColumns(currentDataTable);//模拟实际项目中的一些耗时的异步操作await Task.Delay(500);// 绑定新数据dg.ItemsSource = currentDataTable.DefaultView;_useFirstDataTable = !_useFirstDataTable;}finally{btnUpdate.IsEnabled = true;}
}

问题所在

这段代码存在一个严重的隐藏问题:在 `await Task.Delay(500)` 期间,WPF 会接管 UI 线程并尝试更新视图,在WPF更新UI时,由于当前DataGrid的列和其绑定数据源(DataTable)的字段不一致,会产生多个绑定错误:

image

大量的绑定错误会导致UI卡顿甚至卡死。

为了解决这个问题,我们可以在应用新的列数据之前,将DataGrid的数据源设置为null:

 private async void UpdateButton_Click(object sender, RoutedEventArgs e){// Disable the button during executionbtnUpdate.IsEnabled = false;try{// Toggle between the two data tablesDataTable currentDataTable = _useFirstDataTable ? _dt : _dt2;// Apply columns only
         ApplyDataGridColumns(currentDataTable);// Wait for WPF to update the view with the new columnsawait Task.Delay(500);// Bind the data after delaydg.ItemsSource = currentDataTable.DefaultView;// Toggle for next click_useFirstDataTable = !_useFirstDataTable;}finally{// Re-enable the button after execution completesbtnUpdate.IsEnabled = true;}}

此时,执行ApplyDataGridColumns(currentDataTable)后,WPF更新UI时因为数据源已经被置空,所以不会产生绑定错误,界面不会卡顿。

http://www.jsqmd.com/news/333404/

相关文章:

  • 泉州留学中介十强、2026年性价比高机构全面评析 - 留学机构评审官
  • LLVM Pass快速入门(二):运行第一个pass
  • HighGoDB 用户密码安全策略
  • 2026年高端电子材料权威推荐:医用银浆/导电银胶/耐高温导电胶/可拉伸银浆/烧结银膏/纳米银膏/高导热胶水专业厂家精选 - 品牌推荐官
  • Substance P (1-9) ;RPKPQPFG
  • 深度解析2026年上海留学机构排名,寻找性价比高的优质选择 - 留学机构评审官
  • 深度测评 9个AI论文软件:研究生毕业论文与科研写作必备工具全解析
  • 2026年山东环保工程企业排行榜,细聊盈尚环境工程专业度 - 工业推荐榜
  • 郑州留学机构排名发布,学员满意度高成关键亮点 - 留学机构评审官
  • 2026年安庆口碑好的A-Level课程靠谱机构盘点,哪家值得选 - myqiye
  • DDoS 攻击到底是什么?它的攻击原理全解析!零基础入门到精通,一篇收藏全掌握!
  • 深圳智航精密科技有限公司产品介绍:圆形连接器、防水连接器、密封连接器 - 品致汇
  • sqoop采集做完后导致hdfs数据与Oracle数据量不符的难题。怎么解决?
  • 2026年 红木家具厂家推荐排行榜:东方红木/红木家居,匠心工艺与典雅设计品牌深度解析 - 品牌企业推荐师(官方)
  • 2026年苏州沉水植物厂家排名,沉水植物专业企业哪家性价比高? - mypinpai
  • Attention Isn‘t All You Need for Emotion RecognitionDomain Features Outperform Transformers on the E
  • P0951CE-A FBC01模拟输入模块
  • 2026年深圳性价比高的就业规划机构盘点,就业规划机构哪家好 - 工业品牌热点
  • 基于BS架构的题库管理系统开题报告(3)
  • 学霸同款10个降AIGC工具 千笔·降AIGC助手解决AI率过高痛点
  • P0951BA-0E FBP10处理器模块
  • AI营销内容失灵?2026榜单看原圈科技如何破局伪全球化
  • 聊聊好用的高清LED透明屏,上海地区有哪些品牌 - 工业品网
  • 学生近视低龄化引关注,教育照明护眼灯成防控关键
  • 2026 AI营销内容系统排名:原圈科技如何凭实力登顶榜单?
  • 2026矿用在线浓度计品牌盘点:4家优质厂家产品全解析 - 品牌推荐大师1
  • 口碑好的红点品牌与传达设计奖申报公司,广州有哪些 - 工业设备
  • AI元人文:“正确”之后——论后正确时代的认知生态治理哲学
  • 2026年用友YonSuite哪家靠谱?企业服务合作方选择参考 - 品牌排行榜
  • Lambda anyMatch