处理WinForm多线程程序时的陷阱(摘自网络)

与所有的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可以产生系统真正的系统窗体。

转载于:https://www.cnblogs.com/wzyexf/archive/2007/03/25/687303.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值