如何在不使用字符串名称的情况下引发 PropertyChanged 事件

2024-01-06

如果能够在不显式指定已更改属性的名称的情况下引发“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”。

  1. 我能否确定修剪“b__0”将始终提供正确的属性名称?
  2. 关于财产变更(财产本身)还有其他需要通知的吗?

谢谢。


添加了 C# 6 答案

在 C# 6(以及 Visual Studio 2015 附带的任何版本的 VB)中,我们有nameof运算符,使事情变得比以往更容易。在下面的原始答案中,我使用 C# 5 功能(来电者信息属性)来处理“自我更改”通知的常见情况。这nameof运算符可以在所有情况下使用,并且在“相关属性更改”通知场景中特别有用。

为简单起见,我想我将保留常见的自我更改通知的呼叫者信息属性方法。更少的打字意味着更少的打字错误和复制/粘贴引起的错误的机会......这里的编译器确保您选择有效的类型/成员/变量,但它不能确保您选择正确的类型/成员/变量。然后使用新的就很简单了nameof相关属性更改通知的运算符。下面的示例演示了调用者信息属性的关键行为...如果参数由调用者指定,则该属性对参数没有影响(即,仅当参数被省略时,才为参数值提供调用者信息)呼叫者,召集者)。

还值得观察的是nameofPropertyChanged 事件处理程序也可以使用运算符。现在您可以比较PropertyName事件中的值(这是string)使用特定属性nameof运算符,消除更多魔术字符串。

参考信息nameof here: https://msdn.microsoft.com/en-us/library/dn986596.aspx https://msdn.microsoft.com/en-us/library/dn986596.aspx

Example:

public class Program
{
    void Main()
    {
        var dm = new DataModel();
        dm.PropertyChanged += propertyChangedHandler;
    }

    void propertyChangedHandler(object sender, PropertyChangedEventArgs args)
    {
        if (args.PropertyName == nameof(DataModel.NumberSquared))
        {
            //do something spectacular
        }
    }
}


public class DataModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
    {
        PropertyChangedEventHandler handler = this.PropertyChanged;
        if (handler != null)
        {
            var e = new PropertyChangedEventArgs(propertyName);
            handler(this, e);
        }
    }
}

public class DataModel : DataModelBase
{
    //a simple property
    string _something;
    public string Something 
    { 
        get { return _something; } 
        set { _something = value; OnPropertyChanged(); } 
    }

    //a property with another related property
    int _number;
    public int Number
    {
        get { return _number; }

        set 
        { 
            _number = value; 
            OnPropertyChanged(); 
            OnPropertyChanged(nameof(this.NumberSquared)); 
         }
    }

    //a related property
    public int NumberSquared { get { return Number * Number; } }
}

原始 C# 5 答案

从 C# 5 开始,最好使用调用者信息属性,这在编译时解决,无需反射。

我在基类中实现这个,派生类只需调用OnPropertyChanged方法来自其属性设置器。如果某个属性隐式更改了另一个值,我也可以在属性设置器中使用该方法的“显式”版本,这样就不再“安全”,但这是我接受的罕见情况。

或者,您可以使用此方法进行自我更改通知,并使用 @Jehof 给出的答案进行相关属性更改通知...这将具有没有魔术字符串的优点,并且对于自我更改通知的常见情况具有最快的执行速度。

这个最新的建议在下面实现(我想我会开始使用它!)

public class DataModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
    {
        OnPropertyChangedExplicit(propertyName);
    }

    protected void OnPropertyChanged<TProperty>(Expression<Func<TProperty>> projection)
    {
        var memberExpression = (MemberExpression)projection.Body;
        OnPropertyChangedExplicit(memberExpression.Member.Name);
    }

    void OnPropertyChangedExplicit(string propertyName)
    {
        PropertyChangedEventHandler handler = this.PropertyChanged;
        if (handler != null)
        {
            var e = new PropertyChangedEventArgs(propertyName);
            handler(this, e);
        }
    }
}

public class DataModel : DataModelBase
{
    //a simple property
    string _something;
    public string Something 
    { 
        get { return _something; } 
        set { _something = value; OnPropertyChanged(); } 
    }

    //a property with another related property
    int _number;
    public int Number
    {
        get { return _number; }

        set 
        { 
            _number = value; 
            OnPropertyChanged(); 
            OnPropertyChanged(() => NumberSquared); 
         }
    }

    //a related property
    public int NumberSquared { get { return Number * Number; } }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在不使用字符串名称的情况下引发 PropertyChanged 事件 的相关文章

随机推荐

  • 等高列和垂直对齐列中的图像?

    想知道是否有人可以向我展示在图像列中垂直对齐图像并使列的高度等于文本列的最佳方法 CSS padding 0 margin 0 col width 50 float left height 100 col text background s
  • Mac 上的 Qt MySQL

    我浪费了大约 6 个小时试图按照网上的各种说明让 MySQL 与 Qt 一起工作 我现在就想把自己的手腕砍掉 有谁对如何将 QMYSQL 驱动程序安装到 Qt 中有简单和详细的解释吗 我有 Mac 10 6 我是初学者 我将衷心感谢您的帮助
  • Android 中的 Facebook Like 按钮集成

    我想在我的 Android 应用程序中集成 Facebook Like 按钮 请告诉我如何将其集成到 Android 中的步骤 我会尝试使用包含您从中获得的标准 html 集成的 webview 来完成此操作facebook http de
  • scp 或 sftp 使用单个命令复制多个文件

    我想将文件从远程服务器复制到不同的目录中 例如 我想同时运行这 4 个命令 scp remote A 1 txt local A 1 txt scp remote A 2 txt local A 2 txt scp remote B 1 t
  • 解析推送通知最终在 Android 后台崩溃

    我正在使用 Parse 在 android 中推送通知 但当我关闭 wifi 时 它最终会在后台崩溃 它给了我错误 java lang RuntimeException 无法启动接收器 com parse ParseBroadcastRec
  • 从单个 Hive UDF 创建多个列

    我正在使用 Amazon EMR 和 Hive 0 11 我正在尝试创建一个 Hive UDF 它将从一个 UDF 调用返回多个列 例如 我想调用如下所示的 UDF 并返回几个 命名的 列 SELECT get data columnnam
  • 在 Android 中使用工具栏实现正确的后退导航和主页按钮处理

    我在同一活动中使用单个活动和多个片段 附有屏幕截图 来提供无缝导航 但是在实现了最新的工具栏和导航视图之后 似乎很难处理导航和主页按钮 我在以下方面遇到麻烦 Managing the Hamburger Back button at lef
  • System.Drawing.Point' 到 'System.Windows.Point 的转换器

    我正在尝试在 WPF 中绘制一些实体 我的集合包含 System Drawing Rectangle 对象 当我尝试在 WPF XAML 中访问这些对象的位置时 出现以下错误 无法创建默认转换器来执行类型 System Drawing Po
  • 如何创建带有标签和值的 Winforms 组合框?

    我主要是一名 ASP NET 开发人员 但我正在开发 WinForms 应用程序 并注意到 ASP NET 组合框 html 选择 和 WinForms 之间存在很大差异 我发现 也许是错误的 WinForm 的组合框只有一个 标签 而 A
  • github 操作上下文的完整列表

    在调查如何在 github 操作中 我可以将存储库中特定文件的 基本 版本与文件的拉取请求 头 版本进行比较 在调查这一点时 我发现了各种来源 例如 github community https github community t how
  • Apollo Server Express:请求实体太大

    我需要在 GraphQL 突变中发布大量有效负载 如何提高 Apollo Server 的主体大小限制 我在用着apollo server express版本 2 9 3 我的代码 简化 const myGraphQLSchema new
  • 使用(非类型)枚举参数定义内部类成员函数模板

    我在定义和专门化成员函数时遇到困难update 内部类的Outer
  • 序言中不能有内容

    我正在尝试转换xml到 html 使用xslt 我正在使用java xml transform在java中执行此操作 它工作得很好 直到我遇到了一些xml 它说以下错误 Fatal Error 1 1 Content is not allo
  • 哪个 Linux 进程处理系统调用?

    这可能是一个愚蠢的问题 但我正在使用 gdb 调试一个二进制文件 试图对其进行 逆向工程 并到达一条指令 该指令进行系统调用 之后出现我想要逆向工程的效果 我假设另一个进程正在接管并完成这项工作 所以我想知道是否可以调试使用 gdb 处理系
  • 如何将整数四舍五入到接近百位?

    我不知道我的命名是否正确 无论如何 这些是我拥有的整数 例如 76 121 9660 我想将它们四舍五入到接近一百 例如它们必须变成 100 100 9700 如何在 C 中更快地完成此操作 我想到了一种算法 但也许 C 上有一些实用程序
  • 为什么大多数序列化器使用流而不是字节数组?

    我目前正在开发套接字服务器 我想知道 为什么序列化器喜欢 Xml序列化器 https msdn microsoft com en us library system xml serialization xmlserializer v vs
  • 在 OpenCV 中使用 SURF 测量模式识别的准确性

    我目前正在 OpenCV 中使用 SURF 进行模式识别 到目前为止我有什么 我已经用 C 编写了一个程序 我可以在其中选择源图像和我想要查找的模板 之后 我将两张图片传输到 C dll 中 在其中使用 OpenCV SURFDetecto
  • 对象引用未设置为对象的实例(将列表映射到自动映射器)[重复]

    这个问题在这里已经有答案了 我正在尝试向 dto 添加一个列表 以便使用 AutoMapper 将 dto 顶部映射到实际的上下文类 出于某种原因 当我将列表添加到 dto 的属性并映射它时 在调试时它会抛出错误有这个特例 The obje
  • Spring MVC 4.2+ CORS 返回 403

    我创建了一个新鲜且简单的 Spring MVC 应用程序 使用 4 2 1 Release 现在切换到 4 2 7 Release 该应用程序很简单 WEB XML
  • 如何在不使用字符串名称的情况下引发 PropertyChanged 事件

    如果能够在不显式指定已更改属性的名称的情况下引发 PropertyChanged 事件 那就太好了 我想做这样的事情 public string MyString get return myString set ChangeProperty