.NET 6 MAUI中如何跨线程访问主线程及解决Excel加载异常
跨线程访问主线程与大Excel分表加载解决方案
一、解决跨线程访问主线程的核心方法
MAUI中,绑定到UI控件的ObservableCollection<T>属于UI线程,后台线程直接修改会触发RPC_E_WRONG_THREAD异常。必须通过MAUI提供的线程调度API切换到主线程执行集合更新操作:
方法1:使用MainThread.BeginInvokeOnMainThread
这是跨平台的通用方式,直接将更新逻辑包裹在主线程调度委托中:
// 后台线程处理完数据后 var sheetData = ProcessWorksheet(worksheet); // 切换到主线程更新集合 MainThread.BeginInvokeOnMainThread(() => { foreach (var client in sheetData) { Clients_Colection.Add(client); } });
方法2:使用Dispatcher.Dispatch
如果你的ViewModel继承自BindableBase或持有UI Dispatcher引用,也可以用Dispatcher调度:
Dispatcher.Dispatch(() => { // 批量添加或修改Clients_Colection的逻辑 });
二、大Excel分表加载的优化实现
针对35万单元格+10个工作表的大文件,需结合异步读取、后台处理、批量UI更新来避免卡顿和内存溢出:
1. 用Syncfusion Excel库异步分表读取
利用Syncfusion的ExcelEngine异步API在后台线程处理文件读取,避免阻塞UI:
public async Task LoadExcelDataAsync(string filePath) { await Task.Run(async () => { using var excelEngine = new ExcelEngine(); var application = excelEngine.Excel; application.DefaultVersion = ExcelVersion.Xlsx; using var stream = File.OpenRead(filePath); var workbook = await application.Workbooks.OpenAsync(stream); foreach (var worksheet in workbook.Worksheets) { var sheetClients = await ProcessWorksheetAsync(worksheet); // 切换主线程批量添加数据 MainThread.BeginInvokeOnMainThread(() => { foreach (var client in sheetClients) { Clients_Colection.Add(client); } }); // 给UI线程留出响应时间,避免卡顿 await Task.Delay(50); // 释放当前工作表资源 worksheet.Dispose(); } }); } // 异步处理单个工作表,优化内存占用 private async Task<List<Client>> ProcessWorksheetAsync(IWorksheet worksheet) { var clients = new List<Client>(); var usedRange = worksheet.UsedRange; // 跳过表头行,从第二行开始读取 for (int row = 2; row <= usedRange.LastRow; row++) { // 用DisplayText直接获取公式计算后的结果 var client = new Client { Id = usedRange[row, 1].DisplayText, Name = usedRange[row, 2].DisplayText, // 填充其他字段 }; clients.Add(client); // 每处理1000条数据释放一次线程资源,避免内存暴涨 if (row % 1000 == 0) { await Task.Yield(); } } return clients; }
2. 关键优化点
- 批量UI更新:一次性添加整表数据或分批次添加,减少SfDataGrid的刷新频率
- 资源及时释放:用
using语句和手动Dispose()释放ExcelEngine、Workbook、Worksheet资源 - 避免主线程阻塞:所有文件读取、数据转换逻辑都放在
Task.Run的后台线程中 - 公式处理:用
DisplayText属性直接获取Excel公式计算后的结果,无需手动计算
三、异常原因说明
你遇到的System.Runtime.InteropServices.COMException是因为ObservableCollection<T>并非线程安全,且绑定到UI控件的集合必须在UI线程修改。后台线程直接调用Add_Clients修改集合,导致UI控件访问了其他线程的对象,触发COM线程模型的异常。
内容的提问来源于stack exchange,提问作者OneGarrisonMo
相关产品推荐
相关产品推荐

