
首先要知道什么是委托,用最通俗易懂的话来讲,你就可以把委托看成是用来执行方法(函数)的一个东西。
如何使用委托
在使用委托的时候,你可以像对待一个类一样对待它。即先声明,再实例化。只是有点不同,类在实例化之后叫对象或实例,但委托在实例化后仍叫委托。
声明,如:
namespace Vczx.ProCSharp.Exc
{
delegate double MathsOp( double x )
//class defination here
}
这就声明了一个委托,意义:任何一个返回值为double,且只有一个形禅戚参为double的函数,都可以用这个委托来调用。
注意:委托的声明位置在namespace里面,类的外面。其实,委托的声明也可以在类的里面,甚至是任何一个可以声明类的地方。
实例化:
首先我们要先有一个满足委托声明的方法,假设一个返回一个数的2倍的方法:
class MathsOperations
{
public static double MultiplyBy2( double value )
{
return value * 2
}
}
有了这样一个方法,我氏袭型们就可以实例化一个委托了:
MathsOp operation = new MathsOp( MathsOperations.MultiplyBy2 )
在实例化一个委托时,要给它一个参数,这个参数歼猜就是委托执行的方法,它可以是静态方法,也可以是实例方法(这一点有别于函数指针,函数指针只能调用静态方法),如:
MathsOp operation = new MathsOp( new Class1().Method1 )
在实例化完一个委托之后,就可以用这个委托来调用方法了:
double result = operation( 1.23 )
您可能需要通过线程调用控件的方法或修改一个控件的值:比如修改进度条进度,时会抛出如下错误Cross-thread operation not valid: Control 'XXX' accessed from a thread other than the thread it was created on.
.NET Framework 提供从任何线程都可安全调用的方法,以调用与其他线程所拥有的郑老控件进行交互的方法。
Invoke 方法允许同步执行控件上的方法,而 BeginInvoke 方法则初始化异步执行。要使用这些方法,必须用与将调用的方法相同的签名声明委托。然后,您可以通过向要调用的方法提供适当的委托来调用窗体上任何控件的 Invoke 或 BeginInvoke 方法。任何必需的参数都包装在 Object 中,并被传输到该方法。
调用涉及其他线程所拥有的控件的方法 用与要调用的方法相同的签名声明一个委托。
public delegate void myDelegate(int anInteger, string aString)
使用任何喊笑升控件来调用对其他线程所拥有的控件进行 *** 作的方法。注意: 方法所需的参数(如果有)可在 Object 中提供。
Label1.Invoke(new myDelegate(myMethod), new Object[] {1, "This is the string"})
如果要异步调用方法,请调用 Control.BeginInvoke 方法。
Label1.BeginInvoke(new myDelegate(myMethod), new Object[] {1, "This is the string"})
举个例子:新建一个Windows应用程序项目Win1,在窗体Form1中添加一个Button名称为button1,然后转入代码页,按下面修改代码
using System
using System.Windows.Forms
namespace win1
{
public partial class Form1 : Form
{
public delegate void 我的委托()//声明一个委托
public Form1()
{
InitializeComponent()
}
private void button1_Click(object sender, EventArgs e)//此处先双击button1以便产生代码并且自动创建事件委托
{
new System.Threading.Thread(new System.Threading.ThreadStart (新线程)).Start()//创建一个新的线程并启动
}
public void 设置文字()
{
button1.Text = "Hello"
}
public void 新线程()
{
System.Threading.Thread.Sleep(2000)//线程休眠2秒
button1.BeginInvoke(new 我的委托(设置文字))//在button1所在线程上执行“设置文字”
}
}
}
运行:单击button1,两秒之后文字发生变化
Invoke,BeginInvoke干什么用的,内部是怎么实现的?
这两个方法主要是让给出的方法在控件创建的线程上执行
Invoke使用了Win32API的SendMessage,
BeginInvoke使用了Win32API的PostMessage
这两个方法向UI线程的消息队列中放入一个消息,当UI线程处理这个消息时,就会在自己的上下文中执行传入的方法,换句话说凡是使用BeginInvoke和Invoke调用的线程都是在UI主线程中执行的,所以如果这些方法里涉及一些静态变量,不用考虑加锁的问题
每个线程都有消息队列吗?
不是,只有创建了窗体对象的线程才会有消息队列(下面给出关于这一段的描述)
当一个线程第一次被建立时,系统假定线程不会被用于任何与用户相关的任务。这样可以减少线程对系统资源的要求。但是升大,一旦这个线程调用一个与图形用户界面有关的函数(例如检查它的消息队列或建立一个窗口),系统就会为该线程分配一些另外的资源,以便它能够执行与用户界面有关的任务。特别是,系统分配一个T H R E A D I N F O结构,并将这个数据结构与线程联系起来。
这个T H R E A D I N F O结构包含一组成员变量,利用这组成员,线程可以认为它是在自己独占的环境中运行。T H R E A D I N F O是一个内部的、未公开的数据结构,用来指定线程的登记消息队列(posted-message queue)、发送消息队列( send-message queue)、应答消息队列( r e p l y -message queue)、虚拟输入队列(virtualized-input queue)、唤醒标志(wake flag)、以及用来描述线程局部输入状态的若干变量。图2 6 - 1描述了T H R E A D I N F O结构和与之相联系的三个线程。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)