处理OnPropertyChanged

Mar*_*ijn 33 c# event-handling

我不熟悉基于事件的编程.基本上,我仍然磕磕绊绊.我正在努力设置一些东西,但即使有了教程,我也无法绕过它.我想做的(用语言)如下:

  1. 我有一个属性更改的数据对象.我在属性的setter中注意到这一点,并且想要引发属性已更改的事件.

  2. 在其他地方(完全不同的类),我想知道这个对象的属性已经改变,并采取一些行动.

现在我确定这是一个很常见的场景,但是我的谷歌让我失望了.我只是不了解http://msdn.microsoft.com/en-us/library/ms743695.aspx.

我有这个:

public class ChattyClass {
  private int someMember;

  public event PropertyChangedEventHandler PropertyChanged;

  public int SomeMember {
    get {
      return this.someMember;
    }
    set {
      if (this.someMember != value){
        someMember = value;
        // Raise event/fire handlers. But how?
      }
   }
}

public class NosyClass{
  private List<ChattyClass> myChatters;

  public void addChatter(ChattyClass chatter){
    myChatters.add(chatter);
    // Start listening to property changed events
  }

  private void listner(){
    // I want this to be called when the PropertyChangedEvent is called
    Console.WriteLine("Hey! Hey! Listen! A property of a chatter in my list has changed!");
  }
}
Run Code Online (Sandbox Code Playgroud)

我怎么做才能把它连接起来?

关于评论指向我回到链接:

在示例中,我看到:

protected void OnPropertyChanged(string name)
{
    PropertyChangedEventHandler handler = PropertyChanged;
    if (handler != null)
    {
        handler(this, new PropertyChangedEventArgs(name));
    }
}
Run Code Online (Sandbox Code Playgroud)

我不明白的是:

  • 为什么不这只是呼唤 PropertyChanged(this, new PropertyCHangedEventArgs(name))
  • PropertyChanged在哪里被分配?
  • 作业是什么样的?

Sty*_*xxy 36

你必须解雇这个事件.在MSDN上的示例中,他们创建了一个受保护的方法OnPropertyChanged来处理这个问题(并避免重复代码).

// Create the OnPropertyChanged method to raise the event 
protected void OnPropertyChanged(string name)
{
    PropertyChangedEventHandler handler = PropertyChanged;
    if (handler != null)
    {
        handler(this, new PropertyChangedEventArgs(name));
    }
}
Run Code Online (Sandbox Code Playgroud)

这个方法的作用是查看是否分配了事件处理程序(如果没有分配,你只需要调用它,你就会得到一个NullReferenceException).如果指定了一个,则调用此事件处理程序.提供的事件处理程序必须具有PropertyChangedEventHandler委托的签名.这个签名是:

void MyMethod(object sender, PropertyChangedEventArgs e)
Run Code Online (Sandbox Code Playgroud)

其中第一个参数必须是类型对象,并表示触发事件的对象,第二个参数包含此事件的参数.在这种情况下,您自己的类会触发事件,从而this作为参数提供sender.第二个参数包含已更改的属性的名称.

现在,为了能够对事件的触发作出反应,您必须为该类分配一个事件处理程序.在这种情况下,您必须在addChatter方法中指定它.除此之外,您必须先定义您的处理程序.在你的工作中,NosyClass你必须添加一个方法来做到这一点,例如:

private void chatter_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
    Console.WriteLine("A property has changed: " + e.PropertyName);
}
Run Code Online (Sandbox Code Playgroud)

如您所见,此方法对应于我之前解释过的签名.在第二个参数中,您将能够找到已更改的参数的信息.最后要做的是添加事件处理程序.现在在你的addChatter方法中,你必须分配这个:

public void AddChatter(ChattyClass chatter)
{
    myChatters.Add(chatter);
    // Assign the event handler
    chatter.PropertyChanged += new PropertyChangedEventHandler(chatter_PropertyChanged);
}
Run Code Online (Sandbox Code Playgroud)

我建议你阅读一些关于.NET/C#事件的内容:http://msdn.microsoft.com/en-us/library/awbftdfh.我认为阅读/学习之后,事情会更清楚.

如果您想快速测试它,可以在pastebin上找到一个控制台应用程序(只需复制/粘贴到新的控制台应用程序中).

使用较新版本的C#,您可以内联对事件处理程序的调用:

// inside your setter
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(MyProperty)));
Run Code Online (Sandbox Code Playgroud)

您还可以使用Fody PropertyChanged之类的东西自动生成必要的代码(访问其GitHub页面的链接,带样本).

  • 好的,我知道该物业的名称,但我怎样才能得到它的价值? (2认同)
  • 你做了 100 页微软文档都做不到的事情;通过一个简单且解释良好的示例解释了如何使用基本功能。 (2认同)

Val*_*ale 12

您查找的链接是MVVM模式和WPF.它不是一般的C#实现.你需要这样的东西:

public event EventHandler PropertyChanged;

    public int SomeMember {
        get {
            return this.someMember;
        }
        set {
            if (this.someMember != value) {
                someMember = value;
                if (PropertyChanged != null) { // If someone subscribed to the event
                    PropertyChanged(this, EventArgs.Empty); // Raise the event
                }
            }
        }
Run Code Online (Sandbox Code Playgroud)

...

public void addChatter(ChattyClass chatter) {
    myChatters.add(chatter);
    chatter.PropertyChanged += listner; // Subscribe to the event
}
// This will be called on property changed
private void listner(object sender, EventArgs e){
    Console.WriteLine("Hey! Hey! Listen! A property of a chatter in my list has changed!");
}
Run Code Online (Sandbox Code Playgroud)

如果您想知道哪些属性已更改,您需要将事件定义更改为:

public event PropertyChangedEventHandler PropertyChanged;
Run Code Online (Sandbox Code Playgroud)

并将调用更改为:

public int SomeMember {
    get {
        return this.someMember;
    }
    set {
        if (this.someMember != value){
            someMember = value;
            if (PropertyChanged != null) { // If someone subscribed to the event
                PropertyChanged(this, new PropertyChangedEventArgs("SomeMember")); // Raise the event
            }
        }
   }

   private void listner(object sender, PropertyChangedEventArgs e) {
       string propertyName = e.PropertyName;
       Console.WriteLine(String.Format("Hey! Hey! Listen! a {0} of a chatter in my list has changed!", propertyName));
   }
Run Code Online (Sandbox Code Playgroud)


ken*_*n2k 6

为什么不这只是调用PropertyChanged(这个,新的PropertyCHangedEventArgs(name))

因为如果没有人为事件附加处理程序,则该PropertyChanged对象返回null.因此,在调用它之前,您必须确保它不为null.

PropertyChanged在哪里被分配?

在"监听器"类中.

例如,您可以在其他类中编写:

ChattyClass tmp = new ChattyClass();
tmp.PropertyChanged += (sender, e) =>
    {
        Console.WriteLine(string.Format("Property {0} has been updated", e.PropertyName));
    };
Run Code Online (Sandbox Code Playgroud)

作业是什么样的?

在C#中,我们使用赋值运算符+=-=事件.我建议阅读以下文章,以了解如何使用匿名方法表单(上面的示例)和"旧"表单编写事件处理程序.