如何在不使用字符串名称的情况下引发 PropertyChanged 事件
如果能够在不显式指定已更改属性的名称的情况下引发“PropertyChanged”事件,那就太好了。我想做这样的事情:
public string MyString
{
get { return _myString; }
set
{
ChangePropertyAndNotify<string>(val=>_myString=val, value);
}
}
private void ChangePropertyAndNotify<T>(Action<T> setter, T value)
{
setter(value);
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(setter.Method.Name));
}
}
在这种情况下,收到的名称是 lambda 方法的名称:“
- 我可以确定修剪“
b__0”将始终提供正确的属性名称吗? - 关于财产变更(财产本身)还有其他需要通知的吗?
谢谢。
It would be good to have ability to raise 'PropertyChanged' event without explicit specifying the name of changed property. I would like to do something like this:
public string MyString
{
get { return _myString; }
set
{
ChangePropertyAndNotify<string>(val=>_myString=val, value);
}
}
private void ChangePropertyAndNotify<T>(Action<T> setter, T value)
{
setter(value);
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(setter.Method.Name));
}
}
In this case received name is a name of lambda-method: "<set_MyString>b__0".
- Can I be sure, that trimming "<set_" and ">b__0" will always provide the correct property name?
- Is there any other to notify about property changed (from property himself)?
Thank you.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
添加了 C# 6 答案
在 C# 6(以及 Visual Studio 2015 附带的任何版本的 VB)中,我们有
nameof
运算符,它使事情变得更容易曾经。在下面的原始答案中,我使用 C# 5 功能(来电者信息属性)来处理“自我更改”通知的常见情况。nameof
运算符可以在所有情况下使用,并且在“相关属性更改”通知场景中特别有用。为简单起见,我想我将保留常见的自我更改通知的呼叫者信息属性方法。更少的打字意味着更少的打字错误和复制/粘贴引起的错误的机会......这里的编译器确保您选择有效的类型/成员/变量,但它不能确保您选择正确的类型/成员/变量。使用新的
nameof
运算符来获取相关属性更改通知非常简单。下面的示例演示了调用者信息属性的关键行为...如果参数由调用者指定,则该属性对参数没有影响(即,仅当参数被省略时,才为参数值提供调用者信息)来电者)。还值得注意的是,
nameof
运算符也可以由 PropertyChanged 事件处理程序使用。现在,您可以使用nameof
运算符将事件中的PropertyName
值(这是一个string
)与特定属性进行比较,从而消除更多魔术字符串。nameof
的参考信息位于:https://msdn. microsoft.com/en-us/library/dn986596.aspx示例:
原始 C# 5 答案
从 C# 5 开始,最好使用呼叫者信息属性,这是在编译时解决,无需反射。
我在基类中实现了这一点,派生类只需从其属性设置器中调用
OnPropertyChanged
方法。如果某个属性隐式更改了另一个值,我也可以在属性设置器中使用该方法的“显式”版本,这样就不再“安全”,但这是我接受的罕见情况。或者,您可以使用此方法进行自我更改通知,并使用 @Jehof 给出的答案进行相关属性更改通知...这将具有没有魔术字符串的优点,并且对于自我更改通知的常见情况具有最快的执行速度。
这个最新的建议在下面实现(我想我会开始使用它!)
Added C# 6 Answer
In C# 6 (and whatever version of VB comes with Visual Studio 2015) we have the
nameof
operator which makes things easier than ever. In my original answer below, I use a C# 5 feature (caller info attributes) to handle the common case of "self-changed" notifications. Thenameof
operator can be used in all cases, and is especially useful in the "related-property-changed" notification scenario.For simplicity, I think I'll keep the caller info attribute approach for common self-changed notifications. Less typing means less chances for typos and copy/paste induced bugs... the compiler here ensures that you pick a valid type/member/variable, but it doesn't ensure you pick the correct one. It is simple to then use the new
nameof
operator for related-property change notifications. The example below demonstrates a key behavior of caller info attributes... the attribute has no effect on a parameter if the parameter is specified by the caller (that is, the caller info is provided for the parameter value only when the parameter is omitted by the caller).It is also worth observing that the
nameof
operator can be used by PropertyChanged event handlers as well. Now you can compare thePropertyName
value in the event (which is astring
) to a particular property using thenameof
operator, eliminating more magic strings.Reference info for
nameof
here: https://msdn.microsoft.com/en-us/library/dn986596.aspxExample:
Original C# 5 answer
Since C# 5, best to use caller info attributes, this is resolved at compile time, no reflection necessary.
I implement this in a base class, derived classes just call the
OnPropertyChanged
method from within their property setters. If some property implicitly changes another value, I can use the "Explicit" version of the method in the property setter as well, which then is no longer "safe" but is a rare situation that I just accept.Alternatively you could use this method for self change notifications, and use the answer given by @Jehof for related property change notifications ... this would have the advantage of no magic strings, with the fastest execution for the common case of self change notifications.
This latest suggestion is implemented below (I think I'll start using it!)
更新:原始代码对 Windows Phone 不友好,因为它依赖 LambdaExpression.Compile() 来获取事件源对象。这是更新后的扩展方法(也删除了参数检查):
用法保持如下。
您可以使用调用属性 getter 的 lambda 函数上的反射来获取属性名称。请注意,您实际上不必调用该 lambda,您只需要它来进行反射:
以下是您如何在类中使用该帮助器来引发一个或多个属性的事件:
请注意,该帮助器也是一个 no- op 如果
PropertyChanged
为null
。Update: The original code is not Windows Phone friendly, as it relies on LambdaExpression.Compile() to get the event source object. Here's the updated extension method (with parameter checks removed as well):
The usage stays as below.
You can get the property name using reflection on a lambda function that calls the property getter. note that you don't actually have to invoke that lambda, you just need it for the reflection:
Here's how you can use that helper in your class to raise the event for one or multiple properties:
Note that this helper also is a no-op in case the
PropertyChanged
isnull
.在下面的示例中,您必须传递 3 个值(支持字段、新值、作为 lambda 的属性),但没有魔法字符串,并且仅当属性确实不相等时才会引发属性更改事件。
以下代码包含用于从 lambda 表达式获取属性名称的扩展方法。
最后一些测试代码:
In the following example you have to pass 3 values (backing field, new value, property as lambda) but there are no magic strings and property changed event is only raised when it truly isn't equal.
And the following code contains extension methods to get a property name from a lambda expression.
Finally some test code:
我将扩展方法
与以下方法结合使用。该方法在实现 INotifyPropertyChanged 接口的类中定义(通常是派生其他类的基类)。
然后我可以如下引发 PropertyChanged-Event
使用这种方法,可以轻松重命名属性(在 Visual Studio 中),因为它确保相应的 PropertyChanged 调用也被更新。
I´m using the extension method
in combination with the following method. The method is defined in the class that implements the INotifyPropertyChanged interface (Normally a base class from which my other classes are derived).
Then i can raise the PropertyChanged-Event as follows
Using this approach, its easy to rename Properties (in Visual Studio), cause it ensures that the corresponding PropertyChanged call is updated too.
已发布的解决方案同时存在两个问题:
1)有些要求您创建一个基类并继承它。这是一个巨大的问题,可能会破坏您的类继承链,并导致您开始重新设计您的域,只是为了允许像这样的“额外”开发。
2) 虽然现有解决方案允许您通过 lambda 表达式指定要在哪个属性上触发更改事件,但它们仍然记录和分发属性名称的字符串表示形式,因为它们依赖于现有的 PropertyChangedEventArgs 类。因此,任何实际使用您的 PropertyChanged 事件的代码仍然必须进行字符串比较,这再次破坏了您将来可能需要执行的任何自动重构,更不用说您的编译时支持已经排除在外了首先允许 lambda 表达式而不是字符串的要点之一。
这是我的泛型版本,它遵循 MS 启动的相同事件/委托模式,这意味着不需要基类和扩展方法。
现在您可以在这样的类上使用它:
最后您可以侦听该对象上的事件并使用 lambda 表达式确定更改了哪个属性!
The solutions already posted have a mix of two issues:
1) Some require you to create a base class and inherit from it. This is a huge problem that can throw a wrench in your classes inheritance chain and cause you to start re-designing your domain just to allow a development "extra" like this.
2) While the existing solutions allow you to designate which property to fire the changed event on via a lambda expression they still record and distribute a string representation of the property's name because they rely on the existing PropertyChangedEventArgs class. So any code that actually uses your PropertyChanged event still has to do a string comparison which again breaks any automatic refactoring you may need to do in the future not to mention your compile time support is out the window which is one of the main points of allowing lambda expressions instead of strings in the first place.
This is my generics version which follows the same event/delegate pattern started by MS which means no base classes and no extension methods are necessary.
Now you can use it on a class like this:
And finally you can listen to the events on that object and determine which property changed using a lambda expression as well!
这是我发现的方法:
This is the way I found to do it:
有几种方法可以在不使用属性名的情况下执行此操作。
最好只阅读博客。
http://www.pochet.net/blog /2010/06/25/inotifypropertychanged-implementations-an-overview/
http://justinangel.net/AutomagicallyImplementingINotifyPropertyChanged
There are several approaches to doing this without using a propertyname.
Best to just read the blogs.
http://www.pochet.net/blog/2010/06/25/inotifypropertychanged-implementations-an-overview/
http://justinangel.net/AutomagicallyImplementingINotifyPropertyChanged
我使用一个简单的扩展方法来获取属性名称,以避免魔术字符串出现问题。它还保持了代码的可读性,即它清楚地表明正在发生的事情。
扩展方法如下:
这意味着您的属性集可以抵抗名称更改,如下所示:
我已经写了更多关于此的内容 此处的扩展方法,我已经 在此处发布了匹配的代码片段。
I use a simple extension method to get the property name to avoid problems with magic strings. It also maintains the readability of the code, i.e. it is explicit what is happening.
The extension method is simply as follows:
With this it means that you property sets are resilient against name changes and look like the following:
I've written more about this extension method here and I've published a matching code snippet here.