关于c#:处理OnPropertyChanged

Handling OnPropertyChanged

我不太精通基于事件的编程。基本上,我仍在犹豫。我正在尝试建立一些东西,但是即使有了这些教程,我也无法将我的头围绕在上面。我想做的(用文字)如下:

  • 我有一个数据对象,其中的属性发生了更改。我在属性的setter中注意到这一点,并希望引发一个属性已更改的事件。

  • 在其他地方(在完全不同的类中),我想知道这个对象的属性已经更改,并采取一些措施。

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

    我有这个:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    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!");
      }
    }

    我该怎么做才能把这个连接起来?

    关于我指向链接的评论:

    在我看到的示例中:

    1
    2
    3
    4
    5
    6
    7
    8
    protected void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }

    我不明白的是:

    • 为什么不打电话给PropertyChanged(this, new PropertyCHangedEventArgs(name))
    • 在哪里分配PropertyChanged?
    • 作业是什么样子的?


    你必须启动这个活动。在msdn的例子中,他们提出了一个受保护的方法OnPropertyChanged,以更容易处理这一问题(并避免重复代码)。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // 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委托的签名。此签名是:

    1
    void MyMethod(object sender, PropertyChangedEventArgs e)

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

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

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

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

    1
    2
    3
    4
    5
    6
    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。我认为在阅读/学习这些之后,事情会对你更清楚。

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

    对于较新版本的C,可以将调用内联到事件处理程序中:

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

    您还可以使用一些类似于fody propertychanged的东西来自动生成必要的代码(使用示例访问其Github页面的链接)。


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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    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
                    }
                }
            }

    1
    2
    3
    4
    5
    6
    7
    8
    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!");
    }

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

    1
    public event PropertyChangedEventHandler PropertyChanged;

    并将呼叫更改为:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    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));
       }


    why isn't this just calling PropertyChanged(this, new
    PropertyCHangedEventArgs(name))

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

    where does PropertyChanged get assigned?

    在"Listener"类中。

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

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

    What does the assignment look like?

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


    从使用原始代码,并结合@styxy的答案,我得出:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    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);
        }
    }