C#应用运行时如何解决System.InvalidOperationException异常?
错误原因及解决方案
错误根源
WinForms控件属于单线程组件,所有控件的创建、读取、修改操作都必须在创建它们的UI线程中执行。你用Task启动的后台线程(线程池线程)直接访问richTextBox7.Text、修改richTextBox6.Text等控件属性,违反了线程安全规则,因此抛出System.InvalidOperationException。
解决方案
方案1:用Control.Invoke切换到UI线程操作控件
修改FindVariation方法,所有涉及控件的读写操作都通过Invoke切换回UI线程:
private void FindVariation() { string[] idlist; // 读取richTextBox7内容,切换到UI线程执行 richTextBox7.Invoke(new Action(() => { idlist = richTextBox7.Text.Split('\n'); })); for (int i = 0; i < idlist.Length; i++) { string id = idlist[i].Trim(); if(string.IsNullOrEmpty(id)) continue; string url = "http://www.ebay.com/itm/" + id; HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); using(HttpWebResponse response = (HttpWebResponse)request.GetResponse()) using(StreamReader sr = new StreamReader(response.GetResponseStream())) { string a = sr.ReadToEnd(); string source = string.Join(Environment.NewLine, a.Split(',', ']', '[') .Where(m => m.Length == 12 && m.All(char.IsDigit))); if (!string.IsNullOrEmpty(source)) { // 修改richTextBox6,切换到UI线程 richTextBox6.Invoke(new Action(() => { richTextBox6.Text += id + Environment.NewLine; })); } // 修改richTextBox1,切换到UI线程 richTextBox1.Invoke(new Action(() => { richTextBox1.Text = richTextBox7.Text; })); } } }
方案2:用async/await实现优雅的异步操作(推荐)
这种方式无需手动管理线程,await会自动在异步操作完成后切回UI线程,代码更简洁:
private async Task FindVariationAsync() { // 这里处于UI线程,可直接读取控件 string[] idlist = richTextBox7.Text.Split('\n'); for (int i = 0; i < idlist.Length; i++) { string id = idlist[i].Trim(); if(string.IsNullOrEmpty(id)) continue; string url = "http://www.ebay.com/itm/" + id; HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); // 使用异步方法GetResponseAsync,不阻塞UI线程 using(HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync()) using(StreamReader sr = new StreamReader(response.GetResponseStream())) { string a = await sr.ReadToEndAsync(); string source = string.Join(Environment.NewLine, a.Split(',', ']', '[') .Where(m => m.Length == 12 && m.All(char.IsDigit))); if (!string.IsNullOrEmpty(source)) { // await后自动回到UI线程,可直接修改控件 richTextBox6.Text += id + Environment.NewLine; } richTextBox1.Text = richTextBox7.Text; } } }
调用方式(比如在按钮点击事件中):
private async void btnStart_Click(object sender, EventArgs e) { await FindVariationAsync(); }
注意事项
- 所有WinForms控件的操作必须在UI线程执行,后台线程绝对不能直接读写控件属性
- 用
using语句管理HttpWebResponse和StreamReader,确保网络资源及时释放 async/await是.NET异步编程的标准模式,比手动创建Task+Invoke更易维护
内容的提问来源于stack exchange,提问作者Ryan Gabriel
相关产品推荐
相关产品推荐

