WinForm中调用异步数据库方法等待结果完成的问题
问题描述
我之前看过相关讨论,但那些方案都没用。在我的WinForm应用里,数据库查询只能通过异步方法实现,我需要确保myObjectsList被查询结果填充后,再调用DisplayInTheDatagridview(myObjectsList)。但目前调用该方法时传入的始终是空列表,设置断点等待一会儿就能获取到数据库中的目标数据。我尝试过以下几种实现方式:
public void ShowRowsInDatagridview(List<MyObjects> listRowsToQueryDB) { List<MyObjects> myObjectsList = new List<MyObjects>(); var task = client.GetListFromDBAsync(listRowsToQueryDB); task.Wait(); var result = task.Result; myObjectsList = (List<MyObjects>)result; DisplayInTheDatagridview(myObjectsList); } public void ShowRowsInDatagridview(List<MyObjects> listRowsToQueryDB) { List<MyObjects> myObjectsList = new List<MyObjects>(); var result = client.GetListFromDBAsync(listRowsToQueryDB).GetAwaiter().GetResult(); myObjectsList = (List<MyObjects>)result; DisplayInTheDatagridview(myObjectsList); } public void ShowRowsInDatagridview(List<MyObjects> listRowsToQueryDB) { List<MyObjects> myObjectsList = new List<MyObjects>(); var result = Task.Run(async () => await client.GetListFromDBAsync(listRowsToQueryDB)).Result; myObjectsList = (List<MyObjects>)result; DisplayInTheDatagridview(myObjectsList); }
解决方案
WinForm里直接用Wait()、Result这类阻塞方法很容易触发UI线程死锁,这就是你拿不到数据的核心原因——异步操作被阻塞,根本没机会完成。正确的做法是用async/await模式,同时保证UI线程安全:
正确实现代码
如果是按钮点击这类事件触发的方法,用async void:
private async void ShowRowsInDatagridview(List<MyObjects> listRowsToQueryDB) { // 用await等待异步查询,不会阻塞UI线程 var myObjectsList = await client.GetListFromDBAsync(listRowsToQueryDB) as List<MyObjects>; // 确保在UI线程更新DataGridView(await后默认回到UI线程,这步是保险操作) if (dataGridView1.InvokeRequired) { dataGridView1.Invoke(new Action(() => DisplayInTheDatagridview(myObjectsList))); } else { DisplayInTheDatagridview(myObjectsList); } }
如果是普通工具方法,推荐用async Task:
private async Task ShowRowsInDatagridviewAsync(List<MyObjects> listRowsToQueryDB) { var myObjectsList = await client.GetListFromDBAsync(listRowsToQueryDB) as List<MyObjects>; if (dataGridView1.InvokeRequired) { dataGridView1.Invoke(new Action(() => DisplayInTheDatagridview(myObjectsList))); } else { DisplayInTheDatagridview(myObjectsList); } }
关键说明
await会释放当前UI线程,让异步查询在后台执行,完成后自动切回UI线程(从UI线程发起的await默认会回到UI线程)- 绝对不要用
Wait()、Result这类阻塞方法,它们会让UI线程和异步操作互相等待,直接卡死异步流程 - 如果你断点等待能拿到数据,说明
GetListFromDBAsync本身没问题,就是死锁导致异步操作没机会完成
内容的提问来源于stack exchange,提问作者Tech develop
相关产品推荐
相关产品推荐

