17

这是一个非常简单的问题,但我想知道是否有人可以解释第 4 行实际上在做什么?所以第一行给处理程序一个事件。我真的不知道在什么情况下处理程序将返回 null 或最后一行做什么。

当您向处理程序传递您的对象以及更改了哪个属性时,它对它们做了什么?

PropertyChangedEventHandler handler = PropertyChanged; //property changed is the event

if (handler != null)
{
    handler(this, new PropertyChangedEventArgs(name));
}

我假设我用它来获取此代码,但我想完全了解它在做什么。

4

3 回答 3

38

如果你刚刚这样做:

PropertyChanged(this, new PropertyChangedEventArgs(name))

NullReferenceException如果没有人订阅该事件,您会得到一个PropertyChanged。为了解决这个问题,您添加了一个空检查:

if(PropertyChanged != null)
{
    PropertyChanged(this, new PropertyChangedEventArgs(name))
}

现在,如果您使用多线程,有人可以在 null 检查和事件调用之间取消订阅,所以您仍然可以获得 NullReferenceException. 为了处理它,我们将事件处理程序复制到一个临时变量

  PropertyChangedEventHandler handler = PropertyChanged;
  if (handler != null)
  {
    handler(this, new PropertyChangedEventArgs(name));
  }

现在,如果有人取消订阅该事件,我们的临时变量handler仍将指向旧函数,并且此代码现在无法抛出NullReferenceException.

大多数情况下,您会看到人们使用关键字var来代替,这使得您无需输入临时变量的完整类型,这是您在代码中最常看到的形式。

  var handler = PropertyChanged;
  if (handler != null)
  {
    handler(this, new PropertyChangedEventArgs(name));
  }
于 2013-07-19T01:21:24.733 回答
9

PropertyChanged是这样声明的事件,根据它在接口中的定义:

public event PropertyChangedEventHandler PropertyChanged;

像这样定义的事件实际上是事件处理程序列表的语法糖,您可以通过订阅添加委托(即对函数的引用),或通过取消订阅删除委托。

现在,当您调用一个事件时,即PropertyChanged(...),内部发生的事情是该内部列表中的每个委托都使用参数单独调用。这将告诉您事件的所有订阅者该事件已发生。

现在,handler变量的全部原因是,它PropertyChanged可以为空。如果没有订阅它,那么调用事件(或者更确切地说是事件处理程序列表)将不起作用,所以这只是确保您可以实际执行处理程序的一种方法。

于 2013-07-19T01:19:35.683 回答
6

handler如果没有处理程序订阅事件,则可以为 null ,第四行引发给定属性名称的事件(执行所有订阅的处理程序)。

通常 WPF 框架会在您使用绑定时订阅PropertyChanged,因此一旦绑定的属性发生更改,它就可以更新绑定。

于 2013-07-19T01:12:42.283 回答