1、委托的类型:
Invoke or BeginInvoke
Invoke或者BeginInvoke方法都需要一个委托对象作为参数。委托类似于回调函数的地址,因此调用者通过这两个方法就可以把需要调用的函数地址封送给界面线程。这些方法里面如果包含了更改控件状态的代码,那么由于最终执行这个方法的是界面线程,从而避免了竞争条件,避免了不可预料的问题。如果其它线程直接操作界面线程所属的控件,那么将会产生竞争条件,造成不可预料的结果。
使用BeginInvoke方法封送一个委托方法,类似于使用PostMessage进行通信,这是一个异步方法。也就是该方法封送完毕后马上返回,不会等待委托方法的执行结束,调用者线程将不会被阻塞。但是调用者也可以使用EndInvoke方法或者其它类似WaitHandle机制等待异步操作的完成。使用了EndInvoke方法则会进行阻塞,其效果跟直接使用Invoke效果一样。
但是在内部实现上,Invoke和BeginInvoke都是用了PostMessage方法,从而避免了SendMessage带来的问题。而Invoke方法的同步阻塞是靠WaitHandle机制来完成的。而BeginInvolve跟EndInvoke一样可以实现同步阻塞。
委托方法很好用,下面就列出一个应用场景,其中就是自定义用户控件,当某个大的用户控件是由小的子用户控件组成时,这时小的用户控件的一些事件则需要通过主控件来响应,这时则可以在子用户控件上定义委托事件,然后委托给主用户控件完成。
例子1.修改价格:
其中一个用户控件的代码如此:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CallBack
{
//把委托事件声明在类外面
//public delegate void EditPriceEvent(object price);
public partial class EditPriceItem : UserControl
{
//声明关于事件的委托,其也可以声明在类外面。
public delegate void EditPriceEvent(object price);
//声明一个事件,其中event可以省略
public EditPriceEvent editpriceevent;
public object NowPrice { get; set; }
public void SetPlateDate(object plate)
{
if(plate!=null)
{
this.NowPrice = plate;
TBPrice.Text = (String)this.NowPrice;
}
}
public EditPriceItem()
{
InitializeComponent();
}
private void EditClick(object sender, EventArgs e)
{
//其判断在别处有没有声明这个事件,这是进行事件委托的格式一
if (this.editpriceevent!=null)
{
float value = int.Parse(this.NowPrice.ToString()) + 2;
this.NowPrice = value;
this.editpriceevent.Invoke(this.NowPrice);
}
//进行事件委托格式二,这个要在高版本的VS上才有
//this.editpriceevent?.Invoke(this.NowPrice);
//进行事件委托格式三,
//editpriceevent(this.NowPrice);
}
}
}
注意:这里自定义控件尽量不要使用静态变量、静态函数等能够在不同对象上共享的数据的定义。
其中这主界面里的工程代码是:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CallBack
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
//添加事件响应函数
editPriceItem1.editpriceevent += new EditPriceItem.EditPriceEvent(changeprice);
}
public void changeprice(object price)
{
//把价格显示到主界面
textBox1.Text =price.ToString();
}
private void button1_Click(object sender, EventArgs e)
{
//把价格发送给小用户控件
editPriceItem1.SetPlateDate(textBox1.Text);
}
}
}
其中自定义的用户控件如图:
其中主界面如下: