欢迎光临
我们一直在努力

处理WinForm多线程程序时的陷阱-.NET教程,算法/线程

建站超值云服务器,限时71元/月

与所有的ui开发平台一样,.net下线程开发图形界面同样要遵循一个基本原则:就是对ui对象的操作一定要在产生该ui对象的线程里进行(该线程称作ui线程),因为大部分ui对象都不是线程安全的。

在.net中,把调用调用放在ui线程里执行是通过form类及其子类的invoke()方法实现的(具体的过程请参考其他资料),可以这样做是因为form对象保存了创建它的线程的信息,而且form类有一个bool类型的属性invokerequired,可以通过它查看当前线程是否为创建该form对象的线程(ui线程)——如果为true,则表示当前线程不是ui线程,反之则是。下面提供一个例子:

using system.threading;

using system.windows.forms;

 

namespace csharptest

{

     public class testform : form

     {

         private form form1;

         private form form2;

 

         public static void main()

         {

              testform tf = new testform();

              tf.show();

              tf.uithread();

              application.run();

         }

 

         public void uithread()

         {

              form1 = new form();

              form2 = new form();

              form2.show();//这里是关键

              form1.show();

              thread thread = new thread(new threadstart(workerthread));

              thread.start();

         }

 

         public void workerthread()

         {

              if (form2.invokerequired)

                   form2.invoke(new methodinvoker(workerthread));

              else

              {

                   form1.text = “this is from workerthread.”;

              }

         }

 

         protected override void onclosing(system.componentmodel.canceleventargs e)

         {

              base.onclosing (e);

              application.exit();

         }

     }

}

testform里有两个需要注意的方法,uithread——用来模拟ui线程,workerthread——用来模拟用户线程,uithread中实例化了成员form1与form2,并调用了它们的show方法,在workerthread中改变form1的text属性。请注意workerthread里有个技巧, if (form2.invokerequired) 即如果当前线程不是创建该form2的线程,则将方法通通过过invoke方法放到ui线程里去执行。但就是这里问题出现了。form1和form2都是在uithread里建立的,所以它们保存的线程的信息应该是一样的。所以form1.invokerquired和form2.invokerquired的值在任何线程里都是一样的,即在workerthread中invokerquire的值都应该是true(因为在不同的线程里)。但是如果注释掉form2.show()的话form2.invokerquired在workerthread中的值却是false(在vs.net中调试看到),怎么会这样呢?而且如果不经过判断直接在workerthread里调用form2对象的invoke的话…………居然会抛出异常——“在创建窗口句柄之前,不能在控件上调用 invoke 或 invokeasync”

分析一下该异常的信息,在win32里每一个窗体都有一个窗体句柄,是该窗体在建立时系统分配的,但我们确实在ui线程里建立了form2对象的。这里有个误区.net里的form对象并不是和win32的窗体对象完全对应的。本人窃以为,产生一个form类的实例时,只是产生了一个内存中的普通的对象,并不产生系统窗体(好像叫做user对象吧),只有它第一次呈现在屏幕上(或称作创建)时,才产生系统里表示窗体的user对象且分配句柄,对应的win32 api的createwindow()方法大概也在这个时候执行(先声明:本人对win32 ap 并不熟悉,所以这里如果有什么不妥的话请大家指正)

只有.net里的form对象调用某种方法使系统产生真正的窗体时,form才会有创建它的线程的信息,且invokerquired才有效,即才能调用form的invoke方法。不过我还没弄清楚哪几个方法可以做到。据我所知show, creategraphics可以产生系统真正的系统窗体。

赞(0)
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com 特别注意:本站所有转载文章言论不代表本站观点! 本站所提供的图片等素材,版权归原作者所有,如需使用,请与原作者联系。未经允许不得转载:IDC资讯中心 » 处理WinForm多线程程序时的陷阱-.NET教程,算法/线程
分享到: 更多 (0)