2 using System.Collections;
3 using System.Collections.Generic;
4 using System.Collections.Specialized;
6 namespace Xamarin.Forms.Pages
8 internal class DataSourceList : IList<IDataItem>, IReadOnlyList<IDataItem>, INotifyCollectionChanged
10 readonly List<int> _maskedIndexes = new List<int>(); // Indices
11 readonly HashSet<string> _maskedKeys = new HashSet<string>();
12 IList<IDataItem> _mainList;
14 public IList<IDataItem> MainList
16 get { return _mainList; }
19 var observable = _mainList as INotifyCollectionChanged;
20 if (observable != null)
21 observable.CollectionChanged -= OnMainCollectionChanged;
23 observable = _mainList as INotifyCollectionChanged;
24 if (observable != null)
25 observable.CollectionChanged += OnMainCollectionChanged;
26 _maskedIndexes.Clear();
27 for (var i = 0; i < _mainList.Count; i++)
29 IDataItem data = _mainList[i];
30 if (_maskedKeys.Contains(data.Name))
31 _maskedIndexes.Add(i);
33 OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
37 public IEnumerable<string> MaskedKeys => _maskedKeys;
39 public void Add(IDataItem item)
41 throw new NotSupportedException();
46 throw new NotSupportedException();
49 public bool Contains(IDataItem item)
51 return MainList != null && !_maskedKeys.Contains(item.Name) && MainList.Contains(item);
54 public void CopyTo(IDataItem[] array, int arrayIndex)
56 throw new NotSupportedException();
66 result += MainList.Count;
67 result -= _maskedIndexes.Count;
72 public bool IsReadOnly => true;
74 public bool Remove(IDataItem item)
76 throw new NotSupportedException();
79 IEnumerator IEnumerable.GetEnumerator()
81 return GetEnumerator();
84 public IEnumerator<IDataItem> GetEnumerator()
89 foreach (IDataItem item in MainList)
91 if (!_maskedIndexes.Contains(index))
97 public int IndexOf(IDataItem item)
99 if (_maskedKeys.Contains(item.Name))
102 if (MainList != null)
104 int result = MainList.IndexOf(item);
106 return PublicIndexFromMainIndex(result);
111 public void Insert(int index, IDataItem item)
113 throw new NotSupportedException();
116 public IDataItem this[int index]
120 foreach (int i in _maskedIndexes)
125 if (_mainList == null)
126 throw new IndexOutOfRangeException();
127 return _mainList[index];
129 set { throw new NotSupportedException(); }
132 public void RemoveAt(int index)
134 throw new NotSupportedException();
137 public event NotifyCollectionChangedEventHandler CollectionChanged;
139 public void MaskKey(string key)
141 if (_maskedKeys.Contains(key) || _mainList == null)
143 _maskedKeys.Add(key);
145 foreach (IDataItem item in _mainList)
147 if (item.Name == key)
149 // We need to keep our indexes list sorted, so we insert everything pre-sorted
151 for (var i = 0; i < _maskedIndexes.Count; i++)
153 if (_maskedIndexes[i] > index)
155 _maskedIndexes.Insert(i, index);
161 _maskedIndexes.Add(index);
162 OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, PublicIndexFromMainIndex(index)));
169 public void UnmaskKey(string key)
171 _maskedKeys.Remove(key);
172 if (_mainList == null)
175 foreach (IDataItem item in _mainList)
177 if (item.Name == key)
179 bool removed = _maskedIndexes.Remove(index);
182 OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, PublicIndexFromMainIndex(index)));
190 protected void OnCollectionChanged(NotifyCollectionChangedEventArgs args)
192 CollectionChanged?.Invoke(this, args);
195 void OnMainCollectionChanged(object sender, NotifyCollectionChangedEventArgs args)
197 // much complexity to be had here
200 case NotifyCollectionChangedAction.Add:
201 OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, args.NewItems, PublicIndexFromMainIndex(args.NewStartingIndex)));
203 case NotifyCollectionChangedAction.Move:
204 OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Move, args.OldItems, PublicIndexFromMainIndex(args.NewStartingIndex),
205 PublicIndexFromMainIndex(args.OldStartingIndex)));
207 case NotifyCollectionChangedAction.Remove:
208 OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, args.OldItems, PublicIndexFromMainIndex(args.OldStartingIndex)));
210 case NotifyCollectionChangedAction.Replace:
211 OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, args.NewItems, args.OldItems, PublicIndexFromMainIndex(args.OldStartingIndex)));
213 case NotifyCollectionChangedAction.Reset:
214 OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
217 throw new ArgumentOutOfRangeException();
221 int PublicIndexFromMainIndex(int index)
224 for (var x = 0; x < _maskedIndexes.Count; x++)
226 int i = _maskedIndexes[x];
230 return index - count;