加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

编写高质量代码改善程序的157个建议:第87个建议之区分WPF和WinF

发布时间:2020-12-16 01:18:40 所属栏目:百科 来源:网络整理
导读:??? 今天有时间了,继续《编写高质量代码改善程序的157个建议》的阅读,当我阅读到建议87的时候,里面的一些代码示例和文中所说的不一致了,是不是我现在用的是NetFramework 4.0的缘故,已经把一些问题修复了,今天把问题写下来,告诉大家文中有些小问题需要

??? 今天有时间了,继续《编写高质量代码改善程序的157个建议》的阅读,当我阅读到建议87的时候,里面的一些代码示例和文中所说的不一致了,是不是我现在用的是NetFramework 4.0的缘故,已经把一些问题修复了,今天把问题写下来,告诉大家文中有些小问题需要修复一下。

?? WPF和WinForm窗体应用程序都有一个要求,那就是UI元素(Button,Label,Textbox控件等)必须由创建它的那个线程来更新。WinForm这方面的限制并不是很严格,所以像下面这样的代码,在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 item in ex.InnerExceptions)
         {
             MessageBox.Show(string.Format("异常类型:{0}{1}来自:{2}{3}异常内容:{4}",item.GetType(),Environment.NewLine,item.Source,item.Message));
         }
      }
    },TaskContinuationOptions.OnlyOnFauled);
   t.Start();
}

我把这段代码原封不动的有敲了一遍,但是在我的测试实例里面抛出了异常,截图如下:

现在在Winform里面,我测试过的Task和多线程的操作都会报这个错误,修正这个错误很容易,可以在当前类的构造函数里面增加一下一段代码就可以:

CheckForIllegalCrossThreadCalls = false;

代码效果截图如下:

现在就好了,程序就可以正常运行了,我的文章【其他信息: 线程间操作无效: 从不是创建控件“控件名”的线程访问它。】可以解决这类问题,有详细解释。

所以说,WPF和WinForm都是严格执行主线程操作UI元素的原则。

?处理多线程情况下访问UI控件还有很多方法,现在我就在罗列出一下代码:

 1 Task t =  {
 2            while ()
 3            {
 4                     if (lblResult.InvokeRequired)
 5                     {
 6                         lblResult.BeginInvoke(new Action(() =>
 7                         {
 8                             lblResult.Text = DateTime.Now.ToString();
 9                         }));
10                     }
11                     else
12 13                         lblResult.Text =14 15                     Thread.Sleep();
16                 }
17             });
18             t.ContinueWith((task)=>19                 try
20                 {
21                     task.Wait();
22 23                  (AggregateException ex)
24 25                     foreach (var item  ex.InnerExceptions)
26 27                         MessageBox.Show(28 29 30             },TaskContinuationOptions.OnlyOnFaulted);
31             t.Start();

我们可以模仿WPF处理线程的方法,增加两个新方法,这两个方法是CheckAccess和VerifyAccess,这两个方法是WPF的UI控件的最终积累DispatcherObject类型中的两个方法,代码如下:

 1 namespace System.Windows.Threading
 2  3     //
 4     // 摘要:
 5          表示与 System.Windows.Threading.Dispatcher 关联的对象。
 6     public abstract class DispatcherObject
    {
 8          9         10              初始化 System.Windows.Threading.DispatcherObject 类的新实例。
11         protected DispatcherObject();
12 
13         14         15              获取与此 System.Windows.Threading.DispatcherObject 关联的 System.Windows.Threading.Dispatcher。
16         17          返回结果:
18              调度程序。
19         [EditorBrowsable(EditorBrowsableState.Advanced)]
20         public Dispatcher Dispatcher { get; }
21 
22         23         24              确定调用线程是否可以访问此 System.Windows.Threading.DispatcherObject。
25         26         27              如果调用线程可以访问此对象,则为 true;否则,为 false。
        [EditorBrowsable(EditorBrowsableState.Never)]
29         bool CheckAccess();
30         31         32              强制调用线程具有此 System.Windows.Threading.DispatcherObject 的访问权限。
33         34          异常:
35            T:System.InvalidOperationException:
36              调用线程不可以访问此 System.Windows.Threading.DispatcherObject。
37 38         void VerifyAccess();
39     }
40 }

然后,我们给自己的类型加两个类似的方法,完整代码如下:

 1  partial  Form1 : Form
 3         private Thread mainThread;
 4         public Form1()
        {
 6             InitializeComponent();
        }
 8 
 CheckAccess()
11             return mainThread == Thread.CurrentThread;
13 
 VerifyAccess()
15 16             if (!CheckAccess())
            {
18                 throw new InvalidOperationException(调用线程无法访问对象,因为另一个线程拥有此对象!            }
21         void button1_Click(23             Task t = 24                 25 26                     27 28                         lblResult.BeginInvoke(30                             lblResult.Text =31 32 33                     34 35                         lblResult.Text =36 37                     Thread.Sleep(38 40             t.ContinueWith((task)=>41                 42 43 44 45                 46 47                     48 49                         MessageBox.Show(50 51 52 53             t.Start();
54 55     }

多线程是一个很复杂的话题,我也在学习阶段和总结阶段,有不足的地方,大家多多指教。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读