如果只有一个UI线程,那么如何同时激活多个事件处理程序



我注意到,如果在另一个控件的事件(如LastName_TextChanged(中修改一个控件(例如FirstName.Text = "foo";(的.Text属性,则另一个控制器的事件处理程序(如FirstName_TextChanged(似乎会立即执行,从而中断LastName_TextChanged的执行,然后继续执行。

这是如何与";"单个UI线程";。为什么不按顺序(串行(执行所有事件?

您看到的是"可重入性";,其类似于但重要地不同于";并发";。

具体来说,所有的代码仍然在一个线程中执行。但是,无论对给定事件的处理是否完成,事件都会在发生时引发。类似这样的东西:

public event EventHandler TextChanged
private string _text;
public string Text
{
get => _text;
set
{
_text = value;
TextChanged?.Invoke(this, EventArgs.Empty);
}
}

(以上仅用于说明目的;它并不是事件实际实现的方式,但它确实具有相同的语义。(

当处理程序订阅TextChanged事件时,该处理程序将作为属性setter的一部分被调用。这意味着在对属性的赋值返回给调用者之前引发事件。

如果您有两个不同的对象,并且一个处理程序在处理另一个对象的TextChanged事件时设置了一个对象Text属性,那么在处理程序返回(因为它是作为该处理程序操作的一部分发生的(、引发第一个对象的TextChanged事件之前,第一个对象Text属性的赋值必然会发生,并且第二对象的setter不能返回,直到第二对象CCD_ 11事件的处理程序返回。

您最终会同时执行两个处理程序,因为实际上第一个事件处理程序调用了第二个事件处理函数。它是通过订阅事件的委托间接完成的,但它本质上仍然是一个嵌套的方法调用。它真的和这个没有太大区别:

void M1()
{
M2();
}
void M2()
{
// M1 hasn't returned yet, and yet here we are in M2!
}

也就是说,我们没有问为什么M1()M2()可以在同一线程中同时被调用。在给定的线程中,可以有任意数量的方法在执行,因为每个方法都没有返回。

需要记住的重要一点是,线程的指令指针——确切地说明当前正在执行哪个程序语句的指针——一次只能在方法中。虽然M1()在技术上仍然在执行,因为它还没有返回,但它并没有真正与M2()同时执行。CCD_ 16的执行被搁置,直到CCD_ 17返回为止。

同样,在事件处理程序中,这两个处理程序并不是同时执行的。调用的第一个处理程序的执行在其设置的属性被调用其setter时被搁置,这意味着在调用的第二个处理程序执行时,它也被搁置(因为只有调用该处理程序然后返回,属性setter才会返回(。

最新更新