处理OnPropertyChanged

时间:2012-08-20 09:02:02

标签: c# event-handling

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

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

  2. 在其他地方(完全在另一个类中),我想知道此对象的属性已更改,并采取一些措施。

  3. 现在我确定这是一个很常见的场景,但是我的谷歌让我失望了。我只是不理解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!");
      }
    }
    

    我该怎么做呢?

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

    在我看到的例子中:

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

    我不理解的是:

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

4 个答案:

答案 0 :(得分:34)

你必须解雇这个事件。在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));
    }
}

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

void MyMethod(object sender, PropertyChangedEventArgs e)

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

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

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

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

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

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

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

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

// inside your setter
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(MyProperty)));

您还可以使用类似Fody PropertyChanged的内容自动生成必要的代码(访问其GitHub页面的链接,包含示例)。

答案 1 :(得分:11)

您查看的链接是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
                }
            }
        }

...

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!");
}

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

public event PropertyChangedEventHandler 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, 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));
   }

答案 2 :(得分:6)

  

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

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

  

PropertyChanged在哪里被分配?

在“监听器”类中。

例如,您可以在其他课程中写作:

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

作业是什么样的?

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

答案 3 :(得分:3)

从原始代码开始,并结合@Styxxy的答案,我出来了:

public class ChattyClass  : INotifyPropertyChanged 
{
  private int someMember, otherMember;

  public int SomeMember
  {
      get
      {
          return this.someMember;
      }
      set
      {
          if (this.someMember != value)
          {
              someMember = value;
              OnPropertyChanged("Some Member");
          }
      }
  }

  public int OtherMember
  {
      get
      {
          return this.otherMember;
      }
      set
      {
          if (this.otherMember != value)
          {
              otherMember = value;
              OnPropertyChanged("Other Member");
          }
      }
  }

  protected virtual void OnPropertyChanged(string propertyName)
  {
      PropertyChangedEventHandler handler = PropertyChanged;
      if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
  }

  public event PropertyChangedEventHandler PropertyChanged;

}

public class NosyClass
{
    private List<ChattyClass> myChatters = new List<ChattyClass>();

    public void AddChatter(ChattyClass chatter)
    {
        myChatters.Add(chatter);
        chatter.PropertyChanged+=chatter_PropertyChanged;
    }

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