第一步是关于委托与事件的理解:
在本例中,在Calculator组件(发布者)中定义委托与事件,在frmCalculations(订阅者)中定义事件处理函数。这样的安排可以理解为发布者将事件为委托给订阅者去处理,不同的订阅者,可以有不同的时间处理方法,发布者只提供事件接口。
在frmCalculations(订阅者)的构造函数中添加事件的订阅,而事件的触发是在Calculator组件(发布者)对应的方法中,这些方法在按钮的单击事件中调用,这样按钮的单击就会触发对应的委托事件。
在给例子中委托签名的定义不符合一定的指导方针,一般的指导方针如下:
(1)目标方法的返回类型应为void;
(2)一些订阅者可能要从多个事件发布源接收相同的事件,为了区分不同发布者的事件,签名应包含发布者的标识object sender(不依赖泛型)。
(3)定义实际事件参数(如int number)会将订阅者与发布者耦合起来,因为订阅者需要一组特定参数,以后若要更改这些参数,将影响所有订阅者。采用一个规范的 件参数容器----EventArgs类
综上所述一个规范的委托签名定义如 public delegate void <事件名称>EventHandler(object sender, EventArgs eventArgs);
第二步是关于多线程的理解:
“添加多线程处理功能”在组件中声明多个线程不知道是不是一个好主意,在组件中声明线程,也就意味着要在组件中创建线程和开始线程,这样做是不是合适,以我现在的理解是多个线程的创建和调用是在一个主线程完成的,是不是应该理解Calculator组件是在主线程中的,在组件中创建和调用线程并没有逃离主线程。
“封送对控件的调用”描述的是这样一个问题:跨线程操作控件,像本例中的label,text,button控件都是在主线程中的,从从属线程中调用任何控件都需要“封送处理”调用,本例中从属线程是怎样操作主线程的控件的呢?以FactorialThread为例,该线程的线程方法为Factorial(),在Factorial()中调用了 FactorialComplete(varResult, varTotalAsOfNow);,该事件的处理方法为frmCalculations的
public void FactHandler(double Value, double Calculations)
{
lblFactorial1.Text = Value.ToString();
// Re-enables the button so it can be used again.
btnFactorial1.Enabled = true;
// Updates the label that displays the total calculations performed
lblTotalCalculations.Text = "TotalCalculations are " +
Calculations.ToString();
}
从上面函数可以看出对label控件进行了操作,到这里就可以看出从属线程FactorialThread操作了主线程的label控件。
“影响控件的方法只应该在创建控件的线程上执行,由于从一个线程封送调用并跨线程边界将其发送到另一个线程会耗费大量的系统资源,所以应避免重复调用其他线程上的控件。”,显然本例中是避免不了了,这就属于“不过,在有些情况下,您可能需要通过线程调用控件的方法。”,这种情况下使用
Control.BeginInvoke 方法,可实现异步封送对控件的调用。 要使用次方法,必须用与将调用的方法相同的签名声明委托,如 public delegate void FHandler(double Value, double Calculations);