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的例子中,他们提出了一个受保护的方法
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)); } } |
这个方法的作用是查看是否分配了一个事件处理程序(如果它没有被分配并且您只是调用它,那么您将得到一个
1 | void MyMethod(object sender, PropertyChangedEventArgs e) |
其中第一个参数必须是Object类型,并表示激发事件的对象,第二个参数包含此事件的参数。在这种情况下,您自己的类触发事件,因此将
现在,为了能够在触发事件时做出反应,必须为类分配一个事件处理程序。在这种情况下,您必须在您的
1 2 3 4 | private void chatter_PropertyChanged(object sender, PropertyChangedEventArgs e) { Console.WriteLine("A property has changed:" + e.PropertyName); } |
如您所见,这个方法对应于我之前解释过的签名。在第二个参数中,您将能够找到更改了哪个参数的信息。最后要做的是添加事件处理程序。现在,在您的
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 |
您还可以使用一些类似于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))
因为如果没有人向事件附加处理程序,那么
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); } } |