Simple small INotifyPropertyChanged implementation

后端 未结 6 1529
深忆病人
深忆病人 2021-01-06 07:51

Say I have the following class:

public MainFormViewModel
{
    public String StatusText {get; set;}
}

What is the easiest smallest way to g

6条回答
  •  庸人自扰
    2021-01-06 08:24

    Unfortunately C# doesn't offer an easy mechanism to do that automatically... It has been suggested to create a new syntax like this :

    public observable int Foo { get; set; }
    

    But I doubt it will ever be included in the language...

    A possible solution would to use an AOP framework like Postsharp, that way you just need to decorate your properties with an attribute:

    public MainFormViewModel : INotifyPropertyChanged
    {
        [NotifyPropertyChanged]
        public String StatusText {get; set;}
    }
    

    (haven't tried, but I'm pretty sure Postsharp allows you to do that kind of thing...)


    UPDATE: OK, I managed to make it work. Note that it's a very crude implementation, using reflection on a private field to retrieve the delegate... It could certainly be improved, but I'll leave it to you ;)

    [Serializable]
    public class NotifyPropertyChangedAttribute : LocationInterceptionAspect
    {
        public override void OnSetValue(LocationInterceptionArgs args)
        {
            object oldValue = args.GetCurrentValue();
            object newValue = args.Value;
            base.OnSetValue(args);
            if (args.Instance is INotifyPropertyChanged)
            {
                if (!Equals(oldValue, newValue))
                {
                    RaisePropertyChanged(args.Instance, args.LocationName);
                }
            }
        }
    
        private void RaisePropertyChanged(object instance, string propertyName)
        {
            PropertyChangedEventHandler handler = GetPropertyChangedHandler(instance);
            if (handler != null)
                handler(instance, new PropertyChangedEventArgs(propertyName));
        }
    
        private PropertyChangedEventHandler GetPropertyChangedHandler(object instance)
        {
            Type type = instance.GetType().GetEvent("PropertyChanged").DeclaringType;
            FieldInfo propertyChanged = type.GetField("PropertyChanged",
                                                      BindingFlags.Instance | BindingFlags.NonPublic);
            if (propertyChanged != null)
                return propertyChanged.GetValue(instance) as PropertyChangedEventHandler;
    
            return null;
        }
    }
    

    Note that your class still need to implement the INotifyPropertyChanged interface. You just don't have to explicitly raise the event in your property setters.

提交回复
热议问题