首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >自动INotifyPropertyChanged

自动INotifyPropertyChanged
EN

Stack Overflow用户
提问于 2009-02-09 09:59:10
回答 12查看 34.2K关注 0票数 63

是否有任何方法可以在不需要在每个设置器中编写OnPropertyChanged的情况下自动获得类中属性更改的通知?(我有数以百计的财产,我想知道它们是否发生了变化)。

安东建议动态代理。实际上,我在过去使用过类似的“城堡”库,虽然它确实减少了我必须编写的代码量,但它为我的程序启动时间(ymmv)增加了大约30秒--因为它是一个运行时解决方案。

我想知道是否有编译时解决方案,也许使用编译时属性.

Slashene和TcKs给出了生成重复代码的建议--不幸的是,并不是我所有的属性都是m_Value = value的简单例子--它们中很多都有自定义代码,所以代码片段和xml中的cookie裁剪代码对我的项目也不太可行。

EN

回答 12

Stack Overflow用户

发布于 2009-02-09 11:48:04

2015年7月,在C# 6.0和.NET 4.6以及VS2015中实施了名操作人员的名称。对于C# < 6.0,以下内容仍然有效

我们使用下面的代码(来自http://www.ingebrigtsen.info/post/2008/12/11/INotifyPropertyChanged-revisited.aspx)。伟大的作品:)

代码语言:javascript
复制
public static class NotificationExtensions
{
    #region Delegates

    /// <summary>
    /// A property changed handler without the property name.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="sender">The object that raised the event.</param>
    public delegate void PropertyChangedHandler<TSender>(TSender sender);

    #endregion

    /// <summary>
    /// Notifies listeners about a change.
    /// </summary>
    /// <param name="EventHandler">The event to raise.</param>
    /// <param name="Property">The property that changed.</param>
    public static void Notify(this PropertyChangedEventHandler EventHandler, Expression<Func<object>> Property)
    {
        // Check for null
        if (EventHandler == null)
            return;

        // Get property name
        var lambda = Property as LambdaExpression;
        MemberExpression memberExpression;
        if (lambda.Body is UnaryExpression)
        {
            var unaryExpression = lambda.Body as UnaryExpression;
            memberExpression = unaryExpression.Operand as MemberExpression;
        }
        else
        {
            memberExpression = lambda.Body as MemberExpression;
        }

        ConstantExpression constantExpression;
        if (memberExpression.Expression is UnaryExpression)
        {
            var unaryExpression = memberExpression.Expression as UnaryExpression;
            constantExpression = unaryExpression.Operand as ConstantExpression;
        }
        else
        {
            constantExpression = memberExpression.Expression as ConstantExpression;
        }

        var propertyInfo = memberExpression.Member as PropertyInfo;

        // Invoke event
        foreach (Delegate del in EventHandler.GetInvocationList())
        {
            del.DynamicInvoke(new[]
            {
                constantExpression.Value, new PropertyChangedEventArgs(propertyInfo.Name)
            });
        }
    }


    /// <summary>
    /// Subscribe to changes in an object implementing INotifiyPropertyChanged.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="ObjectThatNotifies">The object you are interested in.</param>
    /// <param name="Property">The property you are interested in.</param>
    /// <param name="Handler">The delegate that will handle the event.</param>
    public static void SubscribeToChange<T>(this T ObjectThatNotifies, Expression<Func<object>> Property, PropertyChangedHandler<T> Handler) where T : INotifyPropertyChanged
    {
        // Add a new PropertyChangedEventHandler
        ObjectThatNotifies.PropertyChanged += (s, e) =>
            {
                // Get name of Property
                var lambda = Property as LambdaExpression;
                MemberExpression memberExpression;
                if (lambda.Body is UnaryExpression)
                {
                    var unaryExpression = lambda.Body as UnaryExpression;
                    memberExpression = unaryExpression.Operand as MemberExpression;
                }
                else
                {
                    memberExpression = lambda.Body as MemberExpression;
                }
                var propertyInfo = memberExpression.Member as PropertyInfo;

                // Notify handler if PropertyName is the one we were interested in
                if (e.PropertyName.Equals(propertyInfo.Name))
                {
                    Handler(ObjectThatNotifies);
                }
            };
    }
}

例如,用这种方式:

代码语言:javascript
复制
public class Employee : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private string _firstName;
    public string FirstName
    {
        get { return this._firstName; }
        set
        {
            this._firstName = value;
            this.PropertyChanged.Notify(()=>this.FirstName);
        }
    }
}

private void firstName_PropertyChanged(Employee sender)
{
    Console.WriteLine(sender.FirstName);
}

employee = new Employee();
employee.SubscribeToChange(() => employee.FirstName, firstName_PropertyChanged);

该示例中可能存在一些语法错误。没试过。但你至少应该有这样的概念:)

编辑:,我现在看到你想要的工作可能更少了,但是是的.上面的东西至少让事情变得简单多了。还可以防止使用字符串引用属性时出现的所有可怕问题。

票数 39
EN

Stack Overflow用户

发布于 2012-09-13 14:25:17

Framework4.5为我们提供了CallerMemberNameAttribute,因此不必将属性名称作为字符串传递:

代码语言:javascript
复制
private string m_myProperty;
public string MyProperty
{
    get { return m_myProperty; }
    set
    {
        m_myProperty = value;
        OnPropertyChanged();
    }
}

private void OnPropertyChanged([CallerMemberName] string propertyName = "none passed")
{
    // ... do stuff here ...
}

类似于Svish的解决方案,只需用无聊的框架功能替换lambda awesomeness;)

如果您正在使用安装了KB2468871的Framework4.0,您可以通过努基特安装Microsoft兼容性包,这也提供了这个属性。

票数 37
EN

Stack Overflow用户

发布于 2009-02-09 10:21:51

实现类型安全的INotifyPropertyChanged看这里

然后制作您自己的代码片段:

代码语言:javascript
复制
private $Type$ _$PropertyName$;
public $Type$ $PropertyName$
{
    get
    {
        return _$PropertyName$;
    }
    set
    {
        if(value != _$PropertyName$)
        {
            _$PropertyName$ = value;
            OnPropertyChanged(o => o.$PropertyName$);               
        }
    }
}

代码片段设计器和你已经做了!构建INotifyPropertyChanged的简单、安全的方法。

票数 11
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/527602

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档