C#中如何为DataGridView异步读取数据?使用EF时出现跨线程错误如何解决?
问题原因
- WinForm的UI控件仅允许由创建它的主线程(UI线程)修改,你在
Task.Run开启的后台工作线程中直接操作dataGridView1的属性和数据源,就会触发跨线程访问异常 - 手动用
Task.Run包装EF查询属于不必要的操作,EF本身提供了原生异步查询方法,性能更优
修复方案
方案1:调整任务逻辑,分离查询和UI操作
将耗时的数据库查询放在后台执行,UI操作移到await之后执行(await默认会捕获UI同步上下文,后续代码自动回到UI线程运行,不会触发跨线程问题)
private async Task FillData() { // 数据库查询逻辑放在后台执行 List<Model.Table_1> dataList = await Task.Run(() => { using (Model.AsyncTestDBEntities db = new Model.AsyncTestDBEntities()) { return db.Table_1.ToList(); } }); // 以下代码在UI线程执行,可安全操作控件 dataGridView1.AutoGenerateColumns = false; dataGridView1.DataSource = dataList; }
方案2:使用EF原生异步方法(更推荐)
先引入EF异步扩展所需的命名空间:using System.Data.Entity;,直接调用EF原生异步方法不需要手动开Task.Run,代码更简洁性能更好
using System.Data.Entity; private async Task FillData() { using (Model.AsyncTestDBEntities db = new Model.AsyncTestDBEntities()) { // 调用EF原生异步查询 List<Model.Table_1> dataList = await db.Table_1.ToListAsync(); dataGridView1.AutoGenerateColumns = false; dataGridView1.DataSource = dataList; } }
额外注意事项
- DbContext属于轻量级对象,用完要及时释放,建议搭配
using语句使用,避免资源泄漏 - 仅在事件处理程序中可以使用
async void写法,其他自定义异步方法请统一返回Task或者Task<T>
内容的提问来源于stack exchange,提问作者CleverWolf
相关产品推荐
相关产品推荐

