`
jelly_bitores
  • 浏览: 45120 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

C#多线程与界面操作c# delegate(委托)与多线程窗体传值

    博客分类:
  • C#
 
阅读更多

c# delegate(委托)与多线程
很多时候写windows程序都需要结合多线程,在.net中用如下得代码来创建并启动一个新的线程。
public void ThreadProc();
Thread thread = new Thread( new ThreadStart( ThreadProc ) );
thread.IsBackground = true;
thread.Start();
但是很多时候,在新的线程中,我们需要与UI进行交互,在.net中不允许我们直接这样做。可以参考MSDN中的描述:
“Windows 窗体”使用单线程单元 (STA) 模型,因为“Windows 窗体”基于本机 Win32 窗口,而 Win32 窗口从本质上而言是单元线程。STA 模型意味着可以在任何线程上创建窗口,但窗口一旦创建后
就不能切换线程,并且对它的所有函数调用都必须在其创建线程上发生。除了 Windows 窗体之外,.NET Framework中的类使用自由线程模型。
STA 模型要求需从控件的非创建线程调用的控件上的任何方法必须被封送到(在其上执行)该控件的创建线程。基类 Control 为此目的提供了若干方法(Invoke、BeginInvoke 和 EndInvoke)。Invoke
生成同步方法调用;BeginInvoke 生成异步方法调用。
Windows 窗体中的控件被绑定到特定的线程,不具备线程安全性。因此,如果从另一个线程调用控件的方法,那么必须使用控件的一个 Invoke 方法来将调用封送到适当的线程。
正如所看到的,我们必须调用Invoke方法,而BeginInvoke可以认为是Invoke的异步版本。调用方法如下:
public delegate void OutDelegate(string text);
public void OutText(string text)
{
     txt.AppendText(text);
     txt.AppendText( "\t\n" );
}
OutDelegate outdelegate = new OutDelegate( OutText );
this.BeginInvoke(outdelegate, new object[]{text});
如果我们需要在另外一个线程里面对UI进行操作,我们需要一个类似OutText的函数,还需要一个该函数的委托delegate,当然,这里展示的是自定义的,.net中还有很多其他类型的委托,可以直接使用
,不需要而外声明。例如:MethodInvoker和EventHandler,这两种类型委托的函数外观是固定的,MethodInvoker是void Function()类型的委托,而EventHandler是void Function(object, EventArgs)
类型的委托,第一个不支持参数,第二中的参数类型和数量都是固定的,这两种委托可以很方便的调用,但是缺乏灵活性。请注意BeginInvoke前面的对象是this,也就是主线程。现在再介绍
Control.InvokeRequired,Control是所有控件的基类,对于这个属性MSDN的描述是:
获取一个值,该值指示调用方在对控件进行方法调用时是否必须调用 Invoke 方法,因为调用方位于创建控件所在的线程以外的线程中。
该属性可用于确定是否必须调用 Invoke 方法,当不知道什么线程拥有控件时这很有用。
也就是说通过判断InvokeRequired可以知道是否需要用委托来调用当前控件的一些方法,如此可以把OutText函数修改一下:
public delegate void OutDelegate(string text);
public void OutText(string text)
{
     if( txt.InvokeRequired )
     {
         OutDelegate outdelegate = new OutDelegate( OutText );
         this.BeginInvoke(outdelegate, new object[]{text});
         return;
     }
     txt.AppendText(text);
     txt.AppendText( "\t\n" );
}
注意,这里的函数没有返回,如果有返回,需要调用Invoke或者EndInvoke来获得返回的结果,不要因为包装而丢失了返回值。如果调用没有完成,Invoke和EndInvoke都将会引起阻塞。
现在如果我有一个线程函数如下:
public void ThreadProc()
{
     for(int i = 0; i < 5; i++)
     {
         OutText( i.ToString() );
         Thread.Sleep(1000);
     }
}
如果循环的次数很大,或者漏了Thread.Sleep(1000);,那么你的UI肯定会停止响应,想知道原因吗?看看BeginInvoke前面的对象,没错,就是this,也就是主线程,当你的主线程不停的调用OutText的
时候,UI当然会停止响应。
与以前VC中创建一个新的线程需要调用AfxBeginThread函数,该函数中第一个参数就是线程函数的地址,而第二个参数是一个类型为LPVOID的指针类型,这个参数将传递给线程函数。现在我们没有办法
再使用这种方法来传递参数了。我们需要将传递给线程的参数和线程函数包装成一个单独的类,然后在这个类的构造函数中初始化该线程所需的参数,然后再将该实例的线程函数传递给Thread类的构造
函数。代码大致如下:
public class ProcClass
{
     private string procParameter = "";
     public ProcClass(string parameter)
     {
         procParameter = parameter;
     }
     public void ThreadProc()
     {
     }
}
ProcClass threadProc = new ProcClass("use thread class");
Thread thread = new Thread( new ThreadStart( threadProc.ThreadProc ) );
thread.IsBackground = true;
thread.Start();
就是这样,需要建立一个中间类来传递线程所需的参数。
那么如果我的线程又需要参数,又需要和UI进行交互的时候该怎么办呢?可以修改一下代码:
public class ProcClass
{
     private string procParameter = "";
     private Form1.OutDelegate delg = null;
     public ProcClass(string parameter, Form1.OutDelegate delg)
     {
         procParameter = parameter;
         this.delg = delg;
     }
     public void ThreadProc()
     {
         delg.BeginInvoke("use ProcClass.ThreadProc()", null, null);
     }
}
ProcClass threadProc = new ProcClass("use thread class", new OutDelegate(OutText));
Thread thread = new Thread( new ThreadStart( threadProc.ThreadProc ) );
thread.IsBackground = true;
thread.Start();
分享到:
评论

相关推荐

    VB.Net-C#多线程Thread-代理委托delegate编程

    最近收集的VB.Net-C#多线程Thread-代理委托delegate编程。文章列表: c#.net多线程同步.txt C#WebBrowser页面与WinForm交互技巧一.txt C#多线程编程-多细全.txt C#多线程编程简单实例.txt C#多线程窗体控件安全访问....

    C#跨窗体(Winform)调用控件(委托回调)

    委托回调

    C#多线程函数如何传参数和返回值[归类].pdf

    "C#多线程函数如何传参数和返回值" 在C#中,多线程函数的参数传递和返回值处理是非常重要的。多线程函数可以使用委托(delegates)来实现参数的传递和返回值的处理。 委托是具有同样参数和返回值的函数的集合。...

    C#多线程操作控件threading的使用

    C#多线程操作控件threading的使用 在C#中,多线程操作控件是一个常见的问题。由于控件是主线程创建的,因此不能直接从另一个线程访问。这篇文章将探讨如何使用threading来实现多线程操作控件。 首先, let's 看一...

    c#等待提示对话框,防止界面假死

    注:this为所要调用等待窗体的主窗体对象,中间为数据传递的委托,显示数据处理的过程.load.showto(this, delegate { hand(new object[] { load, "正在处理数据" }); });中new object[] 第一个参数一定要为固定的...

    c# winform异步不卡界面的实现方法

    子线程的计算结果 要更新到界面中,怎么更新呢,因为不能操作主线程 ,所以要用委托来实现 。 我们来看个例子。 场景 界面上一个按钮加一人richbox , 点击以后获得当前所在年份 代码实现 定义一个委托实现子线程...

    DOTNET-C#基础快速入门教程-全网最简单

    DOTNET_C#基础快速入门教程,100多页的pdf文档,包括了常用的基础知识点: 数据类型 类型转换 变量、常量、运算符 字符串 流程控制 数组 结构、枚举 ...多线程 网络编程 窗体设计 Form窗体 MDI窗体 常用控件

    Winform跨线程操作的简单方法

    分析:label标签控件是主线程创建的,不能直接从另一个线程访问.可以这样认为:不能跨线程直接访问控件; 最简单的办法就是: 代码如下:using System.Windows.Forms;... 您可能感兴趣的文章:在多线程中调用winform窗体

    asp.net知识库

    理解C#中的委托[翻译] 利用委托机制处理.NET中的异常 与正则表达式相关的几个小工具 你真的了解.NET中的String吗? .NET中的方法及其调用(一) 如何判断ArrayList,Hashtable,SortedList 这类对象是否相等 帮助解决...

    net学习笔记及其他代码应用

    26.根据委托(delegate)的知识,请完成以下用户控件中代码片段的填写: namespace test { public delegate void OnDBOperate(); public class UserControlBase : System.Windows.Forms.UserControl { public ...

Global site tag (gtag.js) - Google Analytics