// ----------------------------------------------------------------------- // // Copyright 2014 MIT Licence. See licence.md for more information. // // ----------------------------------------------------------------------- namespace Perspex.Collections { using System; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; using System.Linq; public class PerspexReadOnlyListView : IPerspexReadOnlyList, IDisposable { private IPerspexReadOnlyList source; public PerspexReadOnlyListView() : this(null) { } public PerspexReadOnlyListView(IPerspexReadOnlyList source) { this.source = source; if (source != null) { this.source.CollectionChanged += this.SourceCollectionChanged; } } public event NotifyCollectionChangedEventHandler CollectionChanged; public event PropertyChangedEventHandler PropertyChanged; public int Count { get { return this.source?.Count ?? 0; } } public IPerspexReadOnlyList Source { get { return this.source; } set { if (this.source != null) { this.source.CollectionChanged -= this.SourceCollectionChanged; if (this.CollectionChanged != null) { var ev = new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Remove, this.source, 0); this.CollectionChanged(this, ev); } } this.source = value; if (this.source != null) { this.source.CollectionChanged += this.SourceCollectionChanged; if (this.CollectionChanged != null) { var ev = new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Add, this.source.ToList(), 0); this.CollectionChanged(this, ev); } } } } public T this[int index] { get { return this.source[index]; } } public void Dispose() { this.source.CollectionChanged -= this.SourceCollectionChanged; } public IEnumerator GetEnumerator() { return (this.source != null) ? this.source.GetEnumerator() : Enumerable.Empty().GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); } private void SourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { if (this.CollectionChanged != null) { NotifyCollectionChangedEventArgs ev; switch (e.Action) { case NotifyCollectionChangedAction.Add: ev = new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Add, e.NewItems, e.NewStartingIndex); break; case NotifyCollectionChangedAction.Remove: ev = new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Remove, e.OldItems, e.OldStartingIndex); break; case NotifyCollectionChangedAction.Replace: ev = new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Replace, e.NewItems, e.OldItems, e.OldStartingIndex); break; default: throw new NotSupportedException("Action not yet implemented."); } this.CollectionChanged(this, ev); } } } public class PerspexReadOnlyListView : IPerspexReadOnlyList, IDisposable { private IPerspexReadOnlyList source; private Func convert; public PerspexReadOnlyListView(Func convert) : this(null, convert) { } public PerspexReadOnlyListView(IPerspexReadOnlyList source, Func convert) { this.source = source; this.convert = convert; if (source != null) { this.source.CollectionChanged += this.SourceCollectionChanged; } } public event NotifyCollectionChangedEventHandler CollectionChanged; public event PropertyChangedEventHandler PropertyChanged; public int Count { get { return this.source?.Count ?? 0; } } public IPerspexReadOnlyList Source { get { return this.source; } set { if (this.source != null) { this.source.CollectionChanged -= this.SourceCollectionChanged; if (this.CollectionChanged != null) { var ev = new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Remove, this.ConvertList(this.source), 0); this.CollectionChanged(this, ev); } } this.source = value; if (this.source != null) { this.source.CollectionChanged += this.SourceCollectionChanged; if (this.CollectionChanged != null) { var ev = new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Add, this.ConvertList(this.source), 0); this.CollectionChanged(this, ev); } } } } public TOut this[int index] { get { return (this.convert != null) ? this.convert(this.source[index]) : (TOut)(object)this.source[index]; } } public void Dispose() { if (this.source != null) { this.source.CollectionChanged -= this.SourceCollectionChanged; } } public IEnumerator GetEnumerator() { if (this.source != null) { return this.source.Select(this.convert).GetEnumerator(); } else { return Enumerable.Empty().GetEnumerator(); } } IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); } private IList ConvertList(IEnumerable list) { return list.Cast().Select(this.convert).ToList(); } private void SourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { if (this.CollectionChanged != null) { NotifyCollectionChangedEventArgs ev; switch (e.Action) { case NotifyCollectionChangedAction.Add: ev = new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Add, this.ConvertList(e.NewItems), e.NewStartingIndex); break; case NotifyCollectionChangedAction.Remove: ev = new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Remove, this.ConvertList(e.OldItems), e.OldStartingIndex); break; case NotifyCollectionChangedAction.Replace: ev = new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Replace, this.ConvertList(e.NewItems), this.ConvertList(e.OldItems), e.OldStartingIndex); break; default: throw new NotSupportedException("Action not yet implemented."); } this.CollectionChanged(this, ev); } } } }