簡體   English   中英

具有ValueChanged事件的c#對象,該事件在更改每個屬性時觸發

[英]c# object with a ValueChanged event that fires when each property is changed

用其中一個屬性更改時觸發的事件創建類的最佳方法是什么? 具體來說,您如何向任何訂戶傳達更改了哪個屬性?

例如:

public class ValueChangedPublisher
{
    private int _prop1;
    private string _prop2;

    public static event ValueChangedHandler(/*some parameters?*/);

    public int Prop1
    {
        get { return _prop1; }
        set
        {
            if (_prop1 != value)
            {
                _prop1 = value;
                ValueChangedHandler(/*parameters?*/);
            }
        }
    }

    public string Prop2
    {
        get { return _prop2; }
        set
        {
            if (_prop2 != value)
            {
                _prop2 = value;
                ValueChangedHandler(/*parameters?*/);
            }
        }
    }
}

public class ValueChangedSubscriber
{
    private int _prop1;
    private string _prop2;

    public ValueChangedSubscriber()
    {
        ValueChangedPublisher.ValueChanged += ValueChanged;
    }

    private void ValueChanged(/*parameters?*/)
    {
        /*how does the subscriber know which property was changed?*/
    }
}

我的目標是使它盡可能地可擴展(例如,我不想一堆巨大的if / else if / switch語句四處亂竄)。 有人知道實現我想要的技術嗎?

編輯:真正在尋找的是如何在訂戶端利用INotifyPropertyChanged模式。 我不想這樣做:

private void ValueChanged(string propertyName)
    {
        switch(propertyName)
        {
            case "Prop1":
                _prop1 = _valueChangedPublisher.Prop1;
                break;

            case "Prop2":
                _prop2 = _valueChangedPublisher.Prop2;
                break;

            // the more properties that are added to the publisher, the more cases I
            // have to handle here :/ I don't want to have to do it this way
        }
    }

.NET提供了INotifyPropertyChanged接口 繼承並實現它:

public class ValueChangedPublisher : INotifyPropertyChanged
{
    private int _prop1;
    private string _prop2;

    public event PropertyChangedEventHandler ValueChangedHandler;

    private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public int Prop1
    {
        get { return _prop1; }
        set
        {
            if (_prop1 != value)
            {
                _prop1 = value;
                NotifyPropertyChanged();
            }
        }
    }

    public string Prop2
    {
        get { return _prop2; }
        set
        {
            if (_prop2 != value)
            {
                _prop2 = value;
                NotifyPropertyChanged();
            }
        }
    }
}

這是我為解決問題而做的事情。 它有點大,所以可能沒有表現,但是對我有用。

編輯

有關性能的詳細信息,請參見以下問題: C#使用帶有Delegate.CreateDelegate的值類型的屬性

發布屬性更改內容的基類:

public abstract class PropertyChangePublisherBase : INotifyPropertyChanged
{
    private Dictionary<string, PropertyInfo> _properties;
    private bool _cacheProperties;

    public bool CacheProperties
    {
        get { return _cacheProperties; }
        set
        {
            _cacheProperties = value;

            if (_cacheProperties && _properties == null)
                _properties = new Dictionary<string, PropertyInfo>();
        }
    }

    protected PropertyChangePublisherBase(bool cacheProperties)
    {
        CacheProperties = cacheProperties;
    }

    public bool ContainsBinding(PropertyChangedEventHandler handler)
    {
        if (PropertyChanged == null)
            return false;

        return PropertyChanged.GetInvocationList().Contains(handler);
    }

    public object GetPropertValue(string propertyName)
    {
        if (String.IsNullOrEmpty(propertyName) || String.IsNullOrWhiteSpace(propertyName))
            throw new ArgumentException("Argument must be the name of a property of the current instance.", "propertyName");

        return ProcessGetPropertyValue(propertyName);
    }

    protected virtual object ProcessGetPropertyValue(string propertyName)
    {
        if (_cacheProperties)
        {
            if (_properties.ContainsKey(propertyName))
            {
                return _properties[propertyName].GetValue(this, null);
            }

            else
            {
                var property = GetType().GetProperty(propertyName);
                _properties.Add(propertyName, property);
                return property.GetValue(this, null);
            }
        }

        else
        {
            var property = GetType().GetProperty(propertyName);
            return property.GetValue(this, null);
        }
    }

    #region INotifyPropertyChanged Implementation

    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void RaisePropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;

        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }

    #endregion
}

用於接收屬性更改內容的基類:

public abstract class PropertyChangeSubscriberBase
{
    protected readonly string _propertyName;
    protected virtual object Value { get; set; }

    protected PropertyChangeSubscriberBase(string propertyName, PropertyChangePublisherBase bindingPublisher)
    {
        _propertyName = propertyName;

        AddBinding(propertyName, this, bindingPublisher);
    }

    ~PropertyChangeSubscriberBase()
    {
        RemoveBinding(_propertyName);
    }

    public void Unbind()
    {
        RemoveBinding(_propertyName);
    }

    #region Static Fields

    private static List<string> _bindingNames = new List<string>();
    private static List<PropertyChangeSubscriberBase> _subscribers = new List<PropertyChangeSubscriberBase>();
    private static List<PropertyChangePublisherBase> _publishers = new List<PropertyChangePublisherBase>();

    #endregion

    #region Static Methods

    private static void PropertyChanged(object sender, PropertyChangedEventArgs args)
    {
        string propertyName = args.PropertyName;

        if (_bindingNames.Contains(propertyName))
        {
            int i = _bindingNames.IndexOf(propertyName);
            var publisher = _publishers[i];
            var subscriber = _subscribers[i];

            subscriber.Value = publisher.GetPropertValue(propertyName);
        }
    }

    public static void AddBinding(string propertyName, PropertyChangeSubscriberBase subscriber, PropertyChangePublisherBase publisher)
    {
        if (!_bindingNames.Contains(propertyName))
        {
            _bindingNames.Add(propertyName);
            _publishers.Add(publisher);
            _subscribers.Add(subscriber);

            if (!publisher.ContainsBinding(PropertyChanged))
                publisher.PropertyChanged += PropertyChanged;
        }
    }

    public static void RemoveBinding(string propertyName)
    {
        if (_bindingNames.Contains(propertyName))
        {
            int i = _bindingNames.IndexOf(propertyName);
            var publisher = _publishers[i];

            _bindingNames.RemoveAt(i);
            _publishers.RemoveAt(i);
            _subscribers.RemoveAt(i);

            if (!_publishers.Contains(publisher))
                publisher.PropertyChanged -= PropertyChanged;
        }
    }

    #endregion
}

用於訂閱屬性更改內容的實際類:

public sealed class PropertyChangeSubscriber<T> : PropertyChangeSubscriberBase
{
    private PropertyChangePublisherBase _publisher;

    public new T Value
    {
        get
        {
            if (base.Value == null)
                return default(T);

            if (base.Value.GetType() != typeof(T))
                throw new InvalidOperationException(String.Format("Property {0} on object of type {1} does not match the type Generic type specified {2}.", _propertyName, _publisher.GetType(), typeof(T)));

            return (T)base.Value;
        }

        set { base.Value = value; }
    }

    public PropertyChangeSubscriber(string propertyName, PropertyChangePublisherBase bindingPublisher)
        : base(propertyName, bindingPublisher)
    {
        _publisher = bindingPublisher;
    }
}

這是一個類的示例,具有您希望收到有關其屬性的通知:

public class ExamplePublisher: PropertyChangedPublisherBase
{
    private string _id;
    private bool _testBool;

    public string Id
    {
        get { return _id; }
        set
        {
            if (value == _id) return;
            _id = value;

            RaisePropertyChanged("Id");
        }
    }

    public bool TestBool
    {
        get { return _testBool; }
        set
        {
            if (value.Equals(_testBool)) return;
            _testBool = value;

            RaisePropertyChanged("TestBool");
        }
    }
}

這是當上面的類中的屬性更改時將通知的類的示例:

public class ExampleReceiver
{
    public PropertyChangeSubscriber<string> Id { get; set; }
    public PropertyChangeSubscriber<bool> TestBool { get; set; }

    public MyExampleClass(PropertyChangePublisherBase publisher)
    {
        Id = new PropertyChangeSubscriber<string>("Id", publisher);
        TestBool = new PropertyChangeSubscriber<bool>("TestBool", publisher);
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM