PropertyChanged的主体在哪里?

本文关键字:在哪里 主体 PropertyChanged | 更新日期: 2023-09-27 18:06:47

我想知道PropertyChanged的主体(实例)在哪里?

    private int age;
    public int Age
    {
        get { return age; }
        set 
        { 
            age = value;
            OnPropertyChanged("age");
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
    void OnPropertyChanged(string name)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(name));
    }

在上面,"公共事件PropertyChangedEventHandler PropertyChanged"只是一个声明,但在下一行突然PropertyChanged事件处理程序看起来实例化,然后能够被调用。

要添加一些信息,我使用WPF工作。没有显式的事件订阅者代码。但是在xaml中有一个线索。

<TextBox x:Name="txtAge" Text="{Binding Age}/>

那么,当xaml中有Binding时,是否会自动添加订阅者代码呢?

PropertyChanged的主体在哪里?

这是一个类似于字段的事件。这有点像自动实现的属性——c#编译器提供了实现。(如果语法更像自动实现的属性,我更喜欢它,但那是另一回事。)

来自c# 5规范第10.8.1节:

当编译类似字段的事件时,编译器自动创建存储来保存委托,并为该事件创建访问器,以便向委托字段添加或删除事件处理程序。添加和删除操作是线程安全的,并且可以(但不是必须)在持有实例事件的包含对象的锁(第8.12节)或静态事件的类型对象(第7.6.10.6节)时执行。

因此,实例事件声明的形式为:
class X
{
     public event D Ev;
}

将被编译成相当于:

class X
{
    private D __Ev;  // field to hold the delegate
    public event D Ev {
        add {
            /* add the delegate in a thread safe way */
        }
        remove {
            /* remove the delegate in a thread safe way */
        }
    }
}

在类X中,对+=和- =操作符左侧的Ev的引用导致调用add和remove访问器。所有其他对Ev的引用都被编译为引用隐藏字段__Ev(§7.6.4)。名称"__Ev"是任意的;隐藏字段可以有任何名称,也可以没有名称。

PropertyChanged是一个事件-如果没有人订阅该事件,它将为空,否则它将为非空。您的API用户将像这样订阅:

Person p = new Person(...);
p.PropertyChanged += MyHandler;
void MyHandler(object sender, PropertyChangedEventArgs args) { ... }

同样,你的空检查模式不是100%安全的。在您检查后,它可能从非空变为空。

试试这个:

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

另一个对象(通常)将订阅所提供的事件处理程序PropertyChanged

当条件满足时,类本身将调用它的OnPropertyChanged事件,然后检查它的PropertyChanged事件字段是否为空。如果此字段不为空,这意味着该事件的订阅者已经初始化了它,因此可以调用它。

订阅看起来像这样:

InstanceOfYourClass.PropertyChanged += SomeFunctionThatHandlesIt;
private void SomeFunctionThatHandlesIt(object sender, PropertyChangedEventArgs e)
{
    if (e.PropertyName == "SomeProperty")
    {
        DoSomething();
    }
}