C#异步启动窗体后Task.Result未等待完成的代码修复咨询
问题修复方案
核心问题分析
- 拼写错误:代码中
sampleTask.Reslt是笔误,正确应为sampleTask.Result,但更关键的是直接调用Result会阻塞UI线程,违背你避免卡顿的需求,还存在线程死锁风险。 sampleAsync实现逻辑错误:你用Task.Factory.StartNew开启后台线程后,立刻通过BeginInvoke切回UI线程显示模态窗体,但BeginInvoke是异步调用,后台线程会直接结束,导致sampleTask提前完成,返回的是初始值true,而非窗体关闭后的实际结果。- 不必要的线程切换:
StartProcess本身是快速启动操作,不需要用Task.Run包裹,反而增加线程切换开销。
修复后的代码
1. 修正sampleAsync方法
直接在UI线程异步等待窗体关闭,无需额外后台线程:
public async Task<bool> sampleAsync() { var anotherForm = new AnotherForm(); anotherForm.main = this; // 通过TaskCompletionSource异步等待窗体关闭事件 var tcs = new TaskCompletionSource<bool>(); anotherForm.FormClosed += (s, e) => { tcs.SetResult(anotherForm.rtn); anotherForm.Dispose(); }; anotherForm.Show(); return await tcs.Task; }
2. 修正Button_Click方法
用await替代Result,移除不必要的Task.Run,并修正Teams路径的语法错误:
private async void Button_Click(object sender, EventArgs e) { Task<bool> sampleTask = sampleAsync(); bool rtn = false; if (startOutlookCheckBox.Checked) { rtn = StartProcess(@"C:\Program Files (x86)\Microsoft Office\root\Office16\OUTLOOK.EXE", ""); if (rtn) { await Task.Delay(10000); } } if (startTeamsCheckBox.Checked) { // 修正路径拼接的语法错误 string teamsPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"Microsoft\Teams\Update.exe"); rtn = StartProcess(teamsPath, "--processStart \"Teams.exe\""); if (rtn) { await Task.Delay(5000); } } try { // 用await异步等待任务完成,不会阻塞UI bool taskResult = await sampleTask; if (taskResult) { a(); } else { b(); } } catch (Exception ex) // 异步方法抛出的异常直接捕获,无需AggregateException { Debug.WriteLine(ex.Message); return; } }
3. 修正StartProcess方法(补充变量声明)
private Process startApp; // 补充成员变量声明 private bool StartProcess(string exeFullPath, string param = "") { try { if (File.Exists(exeFullPath)) { startApp = string.IsNullOrEmpty(param) ? Process.Start(exeFullPath) : Process.Start(exeFullPath, param); return true; } else { return false; } } catch (Exception ex) { return false; } }
关键说明
- 用
TaskCompletionSource监听窗体关闭事件,既实现异步等待窗体结果,又不会阻塞主UI线程,能正确获取窗体返回值。 - 用
await sampleTask替代Result,确保异步等待任务完成,避免UI卡顿和线程死锁。 - 移除
StartProcess外层的Task.Run,因为启动进程的操作本身不耗时,无需额外线程切换。
内容的提问来源于stack exchange,提问作者okaken
相关产品推荐
相关产品推荐

