[DataContract(IsReference = true)] [Serializable] public abstract class ChangeNotifier : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected void SetProperty<T>(ref T field, T value, [CallerMemberName] string propertyName = "") protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "") protected void NotifyPropertyChanged(Expression<Func<object, object>> property) protected void NotifyPropertyChanged(Expression<Func<object>> property) protected virtual void OnPropertyChanged(string propertyName) protected ILinkedPropertyChanged AfterNotify(Expression<Func<object> property) protected ILinkedPropertyChanged BeforeNotify(Expression<Func<object>> property) protected ILinkedPropertyChanged AfterNotify<T>(T changeNotifier, Expression<Func<T, object>> property) where T : INotifyPropertyChanged protected ILinkedPropertyChanged BeforeNotify<T>(T changeNotifier, Expression<Func<T, object>> property) where T : ChangeNotifier protected ILinkedObjectChanged Notify(Expression<Func<object>> property) }
public interface ILinkedPropertyChanged { ILinkedPropertyChanged Notify(Expression<Func<object>> targetProperty); ILinkedPropertyChanged Execute(Action action); } public interface ILinkedObjectChanged { ILinkedObjectChanged AfterNotify(Expression<Func<object>> sourceProperty); ILinkedObjectChanged AfterNotify<T>(T sourceChangeNotifier, Expression<Func<T, object>> sourceProperty) where T : INotifyPropertyChanged; ILinkedObjectChanged BeforeNotify(Expression<Func<object>> sourceProperty); ILinkedObjectChanged BeforeNotify<T>(T sourceChangeNotifier, Expression<Func<T, object>> sourceProperty) where T : ChangeNotifier; }
/// <summary> /// . /// </summary> public class Sensor : ChangeNotifier { /// <summary> /// . /// </summary> public int Value { get { return _value; } set { SetProperty(ref _value, value); } } private int _value; /// <summary> /// . /// </summary> public double Delta { get { return _delta; } set { SetProperty(ref _delta, value); } } private double _delta; public Sensor(IAvgValueIndicator indicator) { // BeforeNotify(() => Value).Notify(() => indicator.AvgValue); IValueProvider valueProvider = new RandomValueProvider(); Value = valueProvider.GetValue(this); } } /// <summary> /// , . /// </summary> public class Device : ChangeNotifier, IAvgValueIndicator { /// <summary> /// . /// </summary> private const int SensorsCount = 3; /// <summary> /// . /// </summary> public IReadOnlyCollection<Sensor> Sensors { get { return _sensors; } } private IReadOnlyCollection<Sensor> _sensors; /// <summary> /// . /// </summary> public double AvgValue { get { return (Sensors.Sum(s => s.Value)) / (double)Sensors.Count; } } public Device() { InitSensors(); AfterNotify(() => AvgValue).Execute(UpdateDelta); NotifyPropertyChanged(() => AvgValue); } private void InitSensors() { var sensors = new List<Sensor>(); for (int i = 0; i < SensorsCount; i++) { var sensor = new Sensor(this); //BeforeNotify(sensor, s => s.Value).Notify(() => AvgValue); sensors.Add(sensor); } _sensors = sensors; } private void UpdateDelta() { foreach (var sensor in Sensors) sensor.Delta = Math.Abs(sensor.Value - AvgValue); } }
SetProperty(ref _delta, value); NotifyPropertyChanged(() => AvgValue); AfterNotify(() => AvgValue).Execute(UpdateDelta); BeforeNotify(() => Value).Notify(() => indicator.AvgValue); BeforeNotify(sensor, s => s.Value).Notify(() => AvgValue);
protected void SetProperty<T>(ref T field, T value, [CallerMemberName] string propertyName = "") { if (Equals(field, value)) { return; } field = value; NotifyPropertyChangedInternal(propertyName); }
private void NotifyPropertyChanged(PropertyChangedEventHandler handler, string propertyName) { NotifyLinkedPropertyListeners(propertyName, BeforeChangeLinkedChangeNotifierProperties); if (handler != null) { handler(this, new PropertyChangedEventArgs(propertyName)); } OnPropertyChanged(propertyName); NotifyLinkedPropertyListeners(propertyName, AfterChangeLinkedChangeNotifierProperties); } private void NotifyLinkedPropertyListeners(string propertyName, Dictionary<string, LinkedPropertyChangeNotifierListeners> linkedChangeNotifiers) { LinkedPropertyChangeNotifierListeners changeNotifierListeners; if (linkedChangeNotifiers.TryGetValue(propertyName, out changeNotifierListeners)) { changeNotifierListeners.NotifyAll(); } }
private Dictionary<string, LinkedPropertyChangeNotifierListeners> AfterChangeLinkedChangeNotifierProperties { get { ... } } private Dictionary<string, LinkedPropertyChangeNotifierListeners> BeforeChangeLinkedChangeNotifierProperties { get { ... } }
private class LinkedPropertyChangeNotifierListeners { /// <summary> /// " " - " " /// </summary> private readonly Dictionary<ChangeNotifier, OnNotifyExecuties> _linkedObjects = new Dictionary<ChangeNotifier, OnNotifyExecuties>(); /// <summary> /// . /// </summary> /// <param name="linkedObject"> .</param> /// <param name="targetPropertyName"> .</param> public void Register(ChangeNotifier linkedObject, string targetPropertyName) { var executies = GetOrCreateExecuties(linkedObject); if (!executies.ProprtiesToNotify.Contains(targetPropertyName)) { executies.ProprtiesToNotify.Add(targetPropertyName); } } /// <summary> /// . /// </summary> /// <param name="linkedObject"> .</param> /// <param name="action"> .</param> public void Register(ChangeNotifier linkedObject, Action action) { var executies = GetOrCreateExecuties(linkedObject); if (!executies.ActionsToExecute.Contains(action)) { executies.ActionsToExecute.Add(action); } } /// <summary> /// . /// </summary> /// <param name="linkedObject"> .</param> /// <returns> .</returns> private OnNotifyExecuties GetOrCreateExecuties(ChangeNotifier linkedObject) { OnNotifyExecuties executies; if (!_linkedObjects.TryGetValue(linkedObject, out executies)) { executies = new OnNotifyExecuties(); _linkedObjects.Add(linkedObject, executies); } return executies; } /// <summary> /// . /// </summary> public void NotifyAll() { foreach (var linkedObject in _linkedObjects) { NotifyProperties(linkedObject.Key, linkedObject.Value.ProprtiesToNotify); ExecuteActions(linkedObject.Value.ActionsToExecute); } } /// <summary> /// . /// </summary> /// <param name="linkedObject"> .</param> /// <param name="properties"> .</param> private void NotifyProperties(ChangeNotifier linkedObject, IEnumerable<string> properties) { foreach (var targetProperty in properties) { linkedObject.NotifyPropertyChangedInternal(targetProperty); } } /// <summary> /// . /// </summary> /// <param name="actions"></param> private void ExecuteActions(IEnumerable<Action> actions) { foreach (var action in actions) { action(); } } private class OnNotifyExecuties { private List<string> _proprtiesToNotify; private List<Action> _actionsToExecute; public List<string> ProprtiesToNotify { get { return _proprtiesToNotify ?? (_proprtiesToNotify = new List<string>()); } } public List<Action> ActionsToExecute { get { return _actionsToExecute ?? (_actionsToExecute = new List<Action>()); } } } }
/// <summary> /// . /// </summary> private class BeforeLinkedPropertyChanged : ILinkedPropertyChanged { /// <summary> /// . /// </summary> private readonly ChangeNotifier _sourceChangeNotifier; /// <summary> /// . /// </summary> private readonly string _sourceProperty; /// <summary> /// . /// </summary> private readonly ChangeNotifier _targetChangeNotifier; public BeforeLinkedPropertyChanged(ChangeNotifier sourceChangeNotifier, string sourceProperty, ChangeNotifier targetChangeNotifier) { _sourceChangeNotifier = sourceChangeNotifier; _sourceProperty = sourceProperty; _targetChangeNotifier = targetChangeNotifier; } /// <summary> /// . /// </summary> /// <param name="targetProperty"> .</param> /// <returns>.</returns> public ILinkedPropertyChanged Notify(Expression<Func<object>> targetProperty) { _sourceChangeNotifier.RegisterBeforeLinkedPropertyListener( _sourceProperty, _targetChangeNotifier, (string) targetProperty.GetName()); return this; } /// <summary> /// . /// </summary> /// <param name="action">.</param> /// <returns>.</returns> public ILinkedPropertyChanged Execute(Action action) { _sourceChangeNotifier.RegisterBeforeLinkedPropertyListener( _sourceProperty, _targetChangeNotifier, action); return this; } }
public abstract class ChangeNotifier : INotifyPropertyChanged { ... private void RegisterBeforeLinkedPropertyListener(string linkedPropertyName, ChangeNotifier targetObject, string targetPropertyName) { RegisterLinkedPropertyListener( linkedPropertyName, targetObject, targetPropertyName, BeforeChangeLinkedChangeNotifierProperties); } private void RegisterBeforeLinkedPropertyListener(string linkedPropertyName, ChangeNotifier targetObject, Action action) { RegisterLinkedPropertyListener(linkedPropertyName, targetObject, action, BeforeChangeLinkedChangeNotifierProperties); } private static void RegisterLinkedPropertyListener(string linkedPropertyName, ChangeNotifier targetObject, string targetPropertyName, Dictionary<string, LinkedPropertyChangeNotifierListeners> linkedProperties) { GetOrCreatePropertyListeners(linkedPropertyName, linkedProperties).Register(targetObject, targetPropertyName); } private static void RegisterLinkedPropertyListener(string linkedPropertyName, ChangeNotifier targetObject, Action action, Dictionary<string, LinkedPropertyChangeNotifierListeners> linkedProperties) { GetOrCreatePropertyListeners(linkedPropertyName, linkedProperties).Register(targetObject, action); } private static LinkedPropertyChangeNotifierListeners GetOrCreatePropertyListeners(string linkedPropertyName, Dictionary<string, LinkedPropertyChangeNotifierListeners> linkedProperties) { LinkedPropertyChangeNotifierListeners changeNotifierListeners; if (!linkedProperties.TryGetValue(linkedPropertyName, out changeNotifierListeners)) { changeNotifierListeners = new LinkedPropertyChangeNotifierListeners(); linkedProperties.Add(linkedPropertyName, changeNotifierListeners); } return changeNotifierListeners; } ... }
protected ILinkedPropertyChanged AfterNotify(Expression<Func<object>> property) { var propertyCall = PropertyCallHelper.GetPropertyCall(property); return new AfterLinkedPropertyChanged((INotifyPropertyChanged) propertyCall.TargetObject, propertyCall.TargetPropertyName, this); } protected ILinkedPropertyChanged BeforeNotify(Expression<Func<object>> property) { var propertyCall = PropertyCallHelper.GetPropertyCall(property); return new BeforeLinkedPropertyChanged((ChangeNotifier) propertyCall.TargetObject, propertyCall.TargetPropertyName, this); } protected ILinkedPropertyChanged AfterNotify<T>(T changeNotifier, Expression<Func<T, object>> property) where T : INotifyPropertyChanged { return new AfterLinkedPropertyChanged(changeNotifier, property.GetName(), this); } protected ILinkedPropertyChanged BeforeNotify<T>(T changeNotifier, Expression<Func<T, object>> property) where T : ChangeNotifier { return new BeforeLinkedPropertyChanged(changeNotifier, property.GetName(), this); }
Source: https://habr.com/ru/post/271305/
All Articles