233 строки
5.8 KiB
C#
233 строки
5.8 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Specialized;
|
|
|
|
namespace Xamarin.Forms.Pages
|
|
{
|
|
internal class DataSourceList : IList<IDataItem>, IReadOnlyList<IDataItem>, INotifyCollectionChanged
|
|
{
|
|
readonly List<int> _maskedIndexes = new List<int>(); // Indices
|
|
readonly HashSet<string> _maskedKeys = new HashSet<string>();
|
|
IList<IDataItem> _mainList;
|
|
|
|
public IList<IDataItem> MainList
|
|
{
|
|
get { return _mainList; }
|
|
set
|
|
{
|
|
var observable = _mainList as INotifyCollectionChanged;
|
|
if (observable != null)
|
|
observable.CollectionChanged -= OnMainCollectionChanged;
|
|
_mainList = value;
|
|
observable = _mainList as INotifyCollectionChanged;
|
|
if (observable != null)
|
|
observable.CollectionChanged += OnMainCollectionChanged;
|
|
_maskedIndexes.Clear();
|
|
for (var i = 0; i < _mainList.Count; i++)
|
|
{
|
|
IDataItem data = _mainList[i];
|
|
if (_maskedKeys.Contains(data.Name))
|
|
_maskedIndexes.Add(i);
|
|
}
|
|
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
|
|
}
|
|
}
|
|
|
|
public IEnumerable<string> MaskedKeys => _maskedKeys;
|
|
|
|
public void Add(IDataItem item)
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
|
|
public bool Contains(IDataItem item)
|
|
{
|
|
return MainList != null && !_maskedKeys.Contains(item.Name) && MainList.Contains(item);
|
|
}
|
|
|
|
public void CopyTo(IDataItem[] array, int arrayIndex)
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
|
|
public int Count
|
|
{
|
|
get
|
|
{
|
|
if (MainList == null)
|
|
return 0;
|
|
var result = 0;
|
|
result += MainList.Count;
|
|
result -= _maskedIndexes.Count;
|
|
return result;
|
|
}
|
|
}
|
|
|
|
public bool IsReadOnly => true;
|
|
|
|
public bool Remove(IDataItem item)
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
|
|
IEnumerator IEnumerable.GetEnumerator()
|
|
{
|
|
return GetEnumerator();
|
|
}
|
|
|
|
public IEnumerator<IDataItem> GetEnumerator()
|
|
{
|
|
var index = 0;
|
|
if (MainList == null)
|
|
yield break;
|
|
foreach (IDataItem item in MainList)
|
|
{
|
|
if (!_maskedIndexes.Contains(index))
|
|
yield return item;
|
|
index++;
|
|
}
|
|
}
|
|
|
|
public int IndexOf(IDataItem item)
|
|
{
|
|
if (_maskedKeys.Contains(item.Name))
|
|
return -1;
|
|
|
|
if (MainList != null)
|
|
{
|
|
int result = MainList.IndexOf(item);
|
|
if (result >= 0)
|
|
return PublicIndexFromMainIndex(result);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
public void Insert(int index, IDataItem item)
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
|
|
public IDataItem this[int index]
|
|
{
|
|
get
|
|
{
|
|
foreach (int i in _maskedIndexes)
|
|
{
|
|
if (i <= index)
|
|
index++;
|
|
}
|
|
if (_mainList == null)
|
|
throw new IndexOutOfRangeException();
|
|
return _mainList[index];
|
|
}
|
|
set { throw new NotSupportedException(); }
|
|
}
|
|
|
|
public void RemoveAt(int index)
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
|
|
public event NotifyCollectionChangedEventHandler CollectionChanged;
|
|
|
|
public void MaskKey(string key)
|
|
{
|
|
if (_maskedKeys.Contains(key) || _mainList == null)
|
|
return;
|
|
_maskedKeys.Add(key);
|
|
var index = 0;
|
|
foreach (IDataItem item in _mainList)
|
|
{
|
|
if (item.Name == key)
|
|
{
|
|
// We need to keep our indexes list sorted, so we insert everything pre-sorted
|
|
var added = false;
|
|
for (var i = 0; i < _maskedIndexes.Count; i++)
|
|
{
|
|
if (_maskedIndexes[i] > index)
|
|
{
|
|
_maskedIndexes.Insert(i, index);
|
|
added = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!added)
|
|
_maskedIndexes.Add(index);
|
|
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, PublicIndexFromMainIndex(index)));
|
|
break;
|
|
}
|
|
index++;
|
|
}
|
|
}
|
|
|
|
public void UnmaskKey(string key)
|
|
{
|
|
_maskedKeys.Remove(key);
|
|
if (_mainList == null)
|
|
return;
|
|
var index = 0;
|
|
foreach (IDataItem item in _mainList)
|
|
{
|
|
if (item.Name == key)
|
|
{
|
|
bool removed = _maskedIndexes.Remove(index);
|
|
if (removed)
|
|
{
|
|
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, PublicIndexFromMainIndex(index)));
|
|
}
|
|
break;
|
|
}
|
|
index++;
|
|
}
|
|
}
|
|
|
|
protected void OnCollectionChanged(NotifyCollectionChangedEventArgs args)
|
|
{
|
|
CollectionChanged?.Invoke(this, args);
|
|
}
|
|
|
|
void OnMainCollectionChanged(object sender, NotifyCollectionChangedEventArgs args)
|
|
{
|
|
// much complexity to be had here
|
|
switch (args.Action)
|
|
{
|
|
case NotifyCollectionChangedAction.Add:
|
|
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, args.NewItems, PublicIndexFromMainIndex(args.NewStartingIndex)));
|
|
break;
|
|
case NotifyCollectionChangedAction.Move:
|
|
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Move, args.OldItems, PublicIndexFromMainIndex(args.NewStartingIndex),
|
|
PublicIndexFromMainIndex(args.OldStartingIndex)));
|
|
break;
|
|
case NotifyCollectionChangedAction.Remove:
|
|
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, args.OldItems, PublicIndexFromMainIndex(args.OldStartingIndex)));
|
|
break;
|
|
case NotifyCollectionChangedAction.Replace:
|
|
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, args.NewItems, args.OldItems, PublicIndexFromMainIndex(args.OldStartingIndex)));
|
|
break;
|
|
case NotifyCollectionChangedAction.Reset:
|
|
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
|
|
break;
|
|
default:
|
|
throw new ArgumentOutOfRangeException();
|
|
}
|
|
}
|
|
|
|
int PublicIndexFromMainIndex(int index)
|
|
{
|
|
var count = 0;
|
|
for (var x = 0; x < _maskedIndexes.Count; x++)
|
|
{
|
|
int i = _maskedIndexes[x];
|
|
if (i < index)
|
|
count++;
|
|
}
|
|
return index - count;
|
|
}
|
|
}
|
|
} |