在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
建议87:区分WPF和WinForm的线程模型 private void buttonStartAsync_Click(object sender, EventArgs e) { Task t = new Task(() => { while (true) { label1.Text = DateTime.Now.ToString(); Thread.Sleep(1000); } }); //如果有异常,就启动一个新任务 t.ContinueWith((task) => { try { task.Wait(); } catch (AggregateException ex) { foreach (Exception inner in ex.InnerExceptions) { MessageBox.Show(string.Format("异常类型:{0}{1}来自:{2}{3}异常内容:{4}", inner.GetType(),Environment.NewLine, inner.Source, Environment.NewLine, inner.Message)); } } }, TaskContinuationOptions.OnlyOnFaulted); t.Start(); } 但是,相同的一段代码如果放到WPF环境中,就肯定会抛出System.InvalidOperationException异常。
while (true) { if (label1.InvokeRequired) label1.BeginInvoke(new Action(() => { label1.Text = DateTime.Now.ToString(); })); else label1.Text = DateTime.Now.ToString(); Thread.Sleep(1000); } BeginInvoke方法接受的是一个Delegate类型的参数,在这里我们用一个Action来实现。 //用于表示主线程,在本例中就是UI线程 Thread mainThread; bool CheckAccess() { return mainThread == Thread.CurrentThread; } void VerifyAccess() { if (!CheckAccess()) throw new InvalidOperationException("调用线程无法访问此对象,因为另一个线程拥有此对象"); } private void buttonStartAsync_Click(object sender, EventArgs e) { //当前线程就是主线程 mainThread = Thread.CurrentThread; Task t = new Task(() => { while (true) { if (!CheckAccess()) label1.BeginInvoke(new Action(() => { label1.Text = DateTime.Now.ToString(); })); else label1.Text = DateTime.Now.ToString(); Thread.Sleep(1000); } }); //如果有异常,就启动一个新任务 t.ContinueWith((task) => { try { task.Wait(); } catch (AggregateException ex) { foreach (Exception inner in ex.InnerExceptions) { MessageBox.Show(string.Format("异常类型:{0}{1}来自:{2}{3}异常内容:{4}", inner.GetType(), Environment.NewLine, inner.Source, Environment.NewLine, inner.Message)); } } }, TaskContinuationOptions.OnlyOnFaulted); t.Start(); }
在这段代码中,我们模拟WPF中DispatcherObject的两个方法CheckAccess和VerifyAccess对线程模型进行了重新处理,增强了系统的稳定性。在实际工作中,我们也可以提取这两个方法为扩展方法,以便项目中的所有UI类型都能使用到。 private void buttonStart_Click(object sender, RoutedEventArgs e) { Task t = new Task(() => { while (true) { this.Dispatcher.BeginInvoke(new Action(() => { textBlock1.Text = DateTime.Now.ToString(); })); Thread.Sleep(1000); } }); //为了捕获异常,启动了一个新任务 t.ContinueWith((task) => { try { task.Wait(); } catch (AggregateException ex) { foreach (Exception inner in ex.InnerExceptions) { MessageBox.Show(string.Format("异常类型:{0}{1}来自:{2}{3}异常内容:{4}", inner.GetType(), Environment.NewLine, inner.Source, Environment.NewLine, inner.Message)); } } }, TaskContinuationOptions.OnlyOnFaulted); t.Start(); }
转自:《编写高质量代码改善C#程序的157个建议》陆敏技 |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论