Last active
December 27, 2015 12:39
-
-
Save JohanLarsson/7327483 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| public class ChildPropertyChangedEventArgs : PropertyChangedEventArgs | |
| { | |
| public ChildPropertyChangedEventArgs(object child, string propertyName) | |
| : base(propertyName) | |
| { | |
| Child = child; | |
| } | |
| public ChildPropertyChangedEventArgs(object sender, PropertyChangedEventArgs e) | |
| : base(e.PropertyName) | |
| { | |
| Child = sender; | |
| } | |
| //public ChildPropertyChangedEventArgs(EventPattern<PropertyChangedEventArgs> e) | |
| // : base(e.EventArgs.PropertyName) | |
| //{ | |
| // Child = e.Sender; | |
| //} | |
| public object Child { get; private set; } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| public class OcNpcListener<T> : INotifyPropertyChanged where T : INotifyPropertyChanged | |
| { | |
| private readonly ObservableCollection<T> _collection; | |
| private readonly string _propertyName; | |
| private readonly Dictionary<T, int> _items = new Dictionary<T, int>(new ObjectIdentityComparer()); | |
| public OcNpcListener(ObservableCollection<T> collection, string propertyName = "") | |
| { | |
| _collection = collection; | |
| _propertyName = propertyName ?? ""; | |
| AddRange(collection); | |
| CollectionChangedEventManager.AddHandler(collection, CollectionChanged); | |
| } | |
| private void CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) | |
| { | |
| switch (e.Action) | |
| { | |
| case NotifyCollectionChangedAction.Add: | |
| AddRange(e.NewItems.Cast<T>()); | |
| break; | |
| case NotifyCollectionChangedAction.Remove: | |
| RemoveRange(e.OldItems.Cast<T>()); | |
| break; | |
| case NotifyCollectionChangedAction.Replace: | |
| AddRange(e.NewItems.Cast<T>()); | |
| RemoveRange(e.OldItems.Cast<T>()); | |
| break; | |
| case NotifyCollectionChangedAction.Move: | |
| break; | |
| case NotifyCollectionChangedAction.Reset: | |
| Reset(); | |
| break; | |
| default: | |
| throw new ArgumentOutOfRangeException(); | |
| } | |
| } | |
| private void AddRange(IEnumerable<T> newItems) | |
| { | |
| foreach (T item in newItems) | |
| { | |
| if (_items.ContainsKey(item)) | |
| { | |
| _items[item]++; | |
| } | |
| else | |
| { | |
| _items.Add(item, 1); | |
| PropertyChangedEventManager.AddHandler(item, ChildPropertyChanged, _propertyName); | |
| } | |
| } | |
| } | |
| private void RemoveRange(IEnumerable<T> oldItems) | |
| { | |
| foreach (T item in oldItems) | |
| { | |
| _items[item]--; | |
| if (_items[item] == 0) | |
| { | |
| _items.Remove(item); | |
| PropertyChangedEventManager.RemoveHandler(item, ChildPropertyChanged, _propertyName); | |
| } | |
| } | |
| } | |
| private void Reset() | |
| { | |
| foreach (T item in _items.Keys.ToList()) | |
| { | |
| PropertyChangedEventManager.RemoveHandler(item, ChildPropertyChanged, _propertyName); | |
| _items.Remove(item); | |
| } | |
| AddRange(_collection); | |
| } | |
| public event PropertyChangedEventHandler PropertyChanged; | |
| protected virtual void ChildPropertyChanged(object sender, PropertyChangedEventArgs e) | |
| { | |
| PropertyChangedEventHandler handler = PropertyChanged; | |
| if (handler != null) | |
| handler(this, new ChildPropertyChangedEventArgs(sender, e)); | |
| } | |
| private class ObjectIdentityComparer : IEqualityComparer<T> | |
| { | |
| public bool Equals(T x, T y) | |
| { | |
| return object.ReferenceEquals(x, y); | |
| } | |
| public int GetHashCode(T obj) | |
| { | |
| return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(obj); | |
| } | |
| } | |
| } | |
| public static class OcNpcListener | |
| { | |
| public static OcNpcListener<T> Create<T>(ObservableCollection<T> collection, string propertyName = "") where T : INotifyPropertyChanged | |
| { | |
| return new OcNpcListener<T>(collection, propertyName); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| public class OcNpcListenerTests | |
| { | |
| [Test] | |
| public void SimpleAddTest() | |
| { | |
| var fakeInpc = new FakeInpc(); | |
| var oc = new ObservableCollection<FakeInpc>(); | |
| var events = new List<FakeInpc>(); | |
| var listener = OcNpcListener.Create(oc); | |
| listener.PropertyChanged += (sender, args) => events.Add((FakeInpc)((ChildPropertyChangedEventArgs)args).Child); | |
| Assert.IsFalse(fakeInpc.HasHandler); | |
| oc.Add(fakeInpc); | |
| Assert.IsTrue(fakeInpc.HasHandler); | |
| fakeInpc.Raise1(); | |
| Assert.AreEqual(fakeInpc, events.Single()); | |
| } | |
| [Test] | |
| public void SimpleAddPropertyChangedEventManagerTest() | |
| { | |
| var fakeInpc = new FakeInpc(); | |
| var oc = new ObservableCollection<FakeInpc>(); | |
| var events = new List<FakeInpc>(); | |
| var listener = OcNpcListener.Create(oc); | |
| PropertyChangedEventManager.AddHandler(listener, (sender, args) => events.Add((FakeInpc)((ChildPropertyChangedEventArgs)args).Child), ""); | |
| Assert.IsFalse(fakeInpc.HasHandler); | |
| oc.Add(fakeInpc); | |
| Assert.IsTrue(fakeInpc.HasHandler); | |
| fakeInpc.Raise1(); | |
| Assert.AreEqual(fakeInpc, events.Single()); | |
| } | |
| [Test] | |
| public void SimpleAddNamedTest() | |
| { | |
| var fakeInpc = new FakeInpc(); | |
| var oc = new ObservableCollection<FakeInpc>(); | |
| var events = new List<FakeInpc>(); | |
| var listener = OcNpcListener.Create(oc, "DummyProperty1"); | |
| listener.PropertyChanged += (sender, args) => events.Add((FakeInpc)((ChildPropertyChangedEventArgs)args).Child); | |
| Assert.IsFalse(fakeInpc.HasHandler); | |
| oc.Add(fakeInpc); | |
| Assert.IsTrue(fakeInpc.HasHandler); | |
| fakeInpc.Raise2(); | |
| Assert.IsFalse(events.Any()); | |
| fakeInpc.Raise1(); | |
| Assert.AreEqual(fakeInpc, events.Single()); | |
| } | |
| [Test] | |
| public void AddTwiceRemoveOnceTest() | |
| { | |
| var fakeInpc = new FakeInpc(); | |
| var oc = new ObservableCollection<FakeInpc>(); | |
| var events = new List<FakeInpc>(); | |
| var listener = OcNpcListener.Create(oc);//, (sender, args) => events.Add((FakeInpc)sender)); | |
| listener.PropertyChanged += (sender, args) => events.Add((FakeInpc)((ChildPropertyChangedEventArgs)args).Child); | |
| Assert.IsFalse(fakeInpc.HasHandler); | |
| oc.Add(fakeInpc); | |
| oc.Add(fakeInpc); | |
| Assert.IsTrue(fakeInpc.HasHandler); | |
| fakeInpc.Raise1(); | |
| Assert.AreEqual(fakeInpc, events.Single()); | |
| oc.RemoveAt(1); | |
| Assert.IsTrue(fakeInpc.HasHandler); | |
| } | |
| [Test] | |
| public void RemoveTest() | |
| { | |
| var fakeInpc = new FakeInpc(); | |
| var oc = new ObservableCollection<FakeInpc>(); | |
| var events = new List<FakeInpc>(); | |
| var listener = OcNpcListener.Create(oc);//, (sender, args) => events.Add((FakeInpc)sender)); | |
| listener.PropertyChanged += (sender, args) => events.Add((FakeInpc)((ChildPropertyChangedEventArgs)args).Child); | |
| Assert.IsFalse(fakeInpc.HasHandler); | |
| oc.Add(fakeInpc); | |
| Assert.IsTrue(fakeInpc.HasHandler); | |
| fakeInpc.Raise1(); | |
| Assert.AreEqual(fakeInpc, events.Single()); | |
| oc.Remove(fakeInpc); | |
| Assert.IsFalse(fakeInpc.HasHandler); | |
| } | |
| [Test] | |
| public void ClearTest() | |
| { | |
| var fakeInpc = new FakeInpc(); | |
| var oc = new ObservableCollection<FakeInpc>(); | |
| var events = new List<FakeInpc>(); | |
| var listener = OcNpcListener.Create(oc);//, (sender, args) => events.Add((FakeInpc)sender)); | |
| listener.PropertyChanged += (sender, args) => events.Add((FakeInpc)((ChildPropertyChangedEventArgs)args).Child); | |
| Assert.IsFalse(fakeInpc.HasHandler); | |
| oc.Add(fakeInpc); | |
| Assert.IsTrue(fakeInpc.HasHandler); | |
| fakeInpc.Raise1(); | |
| Assert.AreEqual(fakeInpc, events.Single()); | |
| oc.Clear(); | |
| Assert.IsFalse(fakeInpc.HasHandler); | |
| } | |
| [Test] | |
| public void ReplaceTest() | |
| { | |
| var fakeInpc1 = new FakeInpc(); | |
| var fakeInpc2 = new FakeInpc(); | |
| var oc = new ObservableCollection<FakeInpc>(); | |
| var events = new List<FakeInpc>(); | |
| var listener = OcNpcListener.Create(oc);//, (sender, args) => events.Add((FakeInpc)sender)); | |
| listener.PropertyChanged += (sender, args) => events.Add((FakeInpc)((ChildPropertyChangedEventArgs)args).Child); | |
| Assert.IsFalse(fakeInpc1.HasHandler); | |
| oc.Add(fakeInpc1); | |
| Assert.IsTrue(fakeInpc1.HasHandler); | |
| fakeInpc1.Raise1(); | |
| Assert.AreEqual(fakeInpc1, events.Single()); | |
| oc[0] = fakeInpc2; | |
| Assert.IsFalse(fakeInpc1.HasHandler); | |
| Assert.IsTrue(fakeInpc2.HasHandler); | |
| } | |
| } | |
| public class FakeInpc : INotifyPropertyChanged, IEquatable<FakeInpc> | |
| { | |
| public int DummyProperty1 { get { return 1; } } | |
| public int DummyProperty2 { get { return 2; } } | |
| public void Raise1() | |
| { | |
| OnPropertyChanged("DummyProperty1"); | |
| } | |
| public void Raise2() | |
| { | |
| OnPropertyChanged("DummyProperty2"); | |
| } | |
| public bool HasHandler { get { return PropertyChanged != null; } } | |
| public event PropertyChangedEventHandler PropertyChanged; | |
| [NotifyPropertyChangedInvocator] | |
| protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) | |
| { | |
| var handler = PropertyChanged; | |
| if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); | |
| } | |
| public bool Equals(FakeInpc other) | |
| { | |
| return ReferenceEquals(this, other); | |
| } | |
| public override bool Equals(object obj) | |
| { | |
| if (ReferenceEquals(null, obj)) return false; | |
| if (ReferenceEquals(this, obj)) return true; | |
| if (obj.GetType() != this.GetType()) return false; | |
| return Equals((FakeInpc)obj); | |
| } | |
| public override int GetHashCode() | |
| { | |
| return 3; | |
| } | |
| public static bool operator ==(FakeInpc left, FakeInpc right) | |
| { | |
| return Equals(left, right); | |
| } | |
| public static bool operator !=(FakeInpc left, FakeInpc right) | |
| { | |
| return !Equals(left, right); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment