我不熟悉基于事件的编程。基本上,我仍然磕磕绊绊。我正在努力设置一些东西,但即使有了教程,我也无法绕过它。我想用(用语言)做的是:
我有一个属性更改的数据对象。我在属性的setter中注意到这一点,并且想要引发属性已更改的事件。
在其他地方(完全在另一个类中),我想知道此对象的属性已更改,并采取一些措施。
现在我确定这是一个很常见的场景,但是我的谷歌让我失望了。我只是不理解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))
答案 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);
}
}