diff --git a/mRemoteNGTests/Tools/ObservablePropertyCollectionTests.cs b/mRemoteNGTests/Tools/ObservablePropertyCollectionTests.cs new file mode 100644 index 000000000..33780f8a1 --- /dev/null +++ b/mRemoteNGTests/Tools/ObservablePropertyCollectionTests.cs @@ -0,0 +1,61 @@ +using mRemoteNG.Credential; +using mRemoteNG.Tools; +using NUnit.Framework; + + +namespace mRemoteNGTests.Tools +{ + public class ObservablePropertyCollectionTests + { + private ObservablePropertyCollection _collection; + + [SetUp] + public void Setup() + { + _collection = new ObservablePropertyCollection(); + } + + [Test] + public void WrapsAnExistingList() + { + _collection = new ObservablePropertyCollection(new[] {new CredentialRecord()}); + Assert.That(_collection.Count, Is.EqualTo(1)); + } + + [Test] + public void AddHooksIntoMemberProperty() + { + var wasRaised = false; + _collection.PropertyChanged += (sender, args) => { wasRaised = true; }; + var newItem = new CredentialRecord(); + _collection.Add(newItem); + newItem.Title = "something"; + Assert.That(wasRaised); + } + + [Test] + public void CanClearList() + { + var newItem = new CredentialRecord(); + _collection.Add(newItem); + _collection.Clear(); + Assert.That(_collection.Count, Is.EqualTo(0)); + } + + [Test] + public void ContainsTrue() + { + var newItem = new CredentialRecord(); + _collection.Add(newItem); + Assert.That(_collection.Contains(newItem), Is.True); + } + + [Test] + public void ContainsFalse() + { + var newItem = new CredentialRecord(); + _collection.Add(newItem); + Assert.That(_collection.Contains(new CredentialRecord()), Is.False); + } + } +} \ No newline at end of file diff --git a/mRemoteNGTests/mRemoteNGTests.csproj b/mRemoteNGTests/mRemoteNGTests.csproj index 85967e4b5..c1fed508c 100644 --- a/mRemoteNGTests/mRemoteNGTests.csproj +++ b/mRemoteNGTests/mRemoteNGTests.csproj @@ -137,6 +137,7 @@ + diff --git a/mRemoteV1/Tools/ObservablePropertyCollection.cs b/mRemoteV1/Tools/ObservablePropertyCollection.cs new file mode 100644 index 000000000..02506617f --- /dev/null +++ b/mRemoteV1/Tools/ObservablePropertyCollection.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.ComponentModel; + + +namespace mRemoteNG.Tools +{ + public class ObservablePropertyCollection : IList, INotifyCollectionChanged, INotifyPropertyChanged + where T : INotifyPropertyChanged + { + private readonly ObservableCollection _collection = new ObservableCollection(); + + public int Count => _collection.Count; + public bool IsReadOnly { get; } + + public T this[int index] + { + get { return _collection[index]; } + set { _collection[index] = value; } + } + + public ObservablePropertyCollection() + { + _collection.CollectionChanged += RaiseCollectionChangedEvent; + } + + public ObservablePropertyCollection(IEnumerable list) + { + if (list == null) + throw new ArgumentNullException(nameof(list)); + + foreach(var item in list) + Add(item); + _collection.CollectionChanged += RaiseCollectionChangedEvent; + } + + public void Add(T item) + { + if (_collection.Contains(item)) return; + _collection.Add(item); + item.PropertyChanged += RaisePropertyChangedEvent; + } + + public void Insert(int index, T item) + { + if (_collection.Contains(item)) return; + _collection.Insert(index, item); + item.PropertyChanged += RaisePropertyChangedEvent; + } + + public bool Remove(T item) + { + if (!_collection.Contains(item)) return false; + item.PropertyChanged -= RaisePropertyChangedEvent; + return _collection.Remove(item); + } + + public void RemoveAt(int index) + { + var removalTarget = _collection[index]; + if (removalTarget == null) return; + _collection.Remove(removalTarget); + } + + public void Clear() + { + foreach (var item in _collection) + item.PropertyChanged -= RaisePropertyChangedEvent; + _collection.Clear(); + } + + public IEnumerator GetEnumerator() => _collection.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + public bool Contains(T item) => _collection.Contains(item); + public void CopyTo(T[] array, int arrayIndex) => _collection.CopyTo(array, arrayIndex); + public int IndexOf(T item) => _collection.IndexOf(item); + + + public event NotifyCollectionChangedEventHandler CollectionChanged; + public event PropertyChangedEventHandler PropertyChanged; + + private void RaiseCollectionChangedEvent(object sender, NotifyCollectionChangedEventArgs args) + { + CollectionChanged?.Invoke(this, args); + } + + private void RaisePropertyChangedEvent(object sender, PropertyChangedEventArgs propertyChangedEventArgs) + { + PropertyChanged?.Invoke(sender, propertyChangedEventArgs); + } + } +} \ No newline at end of file diff --git a/mRemoteV1/mRemoteV1.csproj b/mRemoteV1/mRemoteV1.csproj index bb4f879ed..793c8ba6a 100644 --- a/mRemoteV1/mRemoteV1.csproj +++ b/mRemoteV1/mRemoteV1.csproj @@ -224,6 +224,7 @@ +