зеркало из https://github.com/DeGsoft/maui-linux.git
256 строки
6.6 KiB
C#
256 строки
6.6 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.Collections.Specialized;
|
|
using System.Linq;
|
|
|
|
namespace Xamarin.Forms
|
|
{
|
|
internal class ObservableWrapper<TTrack, TRestrict> : IList<TRestrict>, INotifyCollectionChanged where TTrack : Element where TRestrict : TTrack
|
|
{
|
|
readonly ObservableCollection<TTrack> _list;
|
|
|
|
public ObservableWrapper(ObservableCollection<TTrack> list)
|
|
{
|
|
if (list == null)
|
|
throw new ArgumentNullException("list");
|
|
|
|
_list = list;
|
|
|
|
list.CollectionChanged += ListOnCollectionChanged;
|
|
}
|
|
|
|
public void Add(TRestrict item)
|
|
{
|
|
if (item == null)
|
|
throw new ArgumentNullException("item");
|
|
if (IsReadOnly)
|
|
throw new NotSupportedException("The collection is read-only.");
|
|
|
|
if (_list.Contains(item))
|
|
return;
|
|
|
|
item.Owned = true;
|
|
_list.Add(item);
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
if (IsReadOnly)
|
|
throw new NotSupportedException("The collection is read-only.");
|
|
|
|
foreach (TRestrict item in _list.OfType<TRestrict>().ToArray())
|
|
{
|
|
_list.Remove(item);
|
|
item.Owned = false;
|
|
}
|
|
}
|
|
|
|
public bool Contains(TRestrict item)
|
|
{
|
|
return item.Owned && _list.Contains(item);
|
|
}
|
|
|
|
public void CopyTo(TRestrict[] array, int destIndex)
|
|
{
|
|
if (array.Length - destIndex < Count)
|
|
throw new ArgumentException("Destination array was not long enough. Check destIndex and length, and the array's lower bounds.");
|
|
foreach (TRestrict item in this)
|
|
{
|
|
array[destIndex] = item;
|
|
destIndex++;
|
|
}
|
|
}
|
|
|
|
public int Count
|
|
{
|
|
get { return _list.Where(i => i.Owned).OfType<TRestrict>().Count(); }
|
|
}
|
|
|
|
public bool IsReadOnly { get; internal set; }
|
|
|
|
public bool Remove(TRestrict item)
|
|
{
|
|
if (item == null)
|
|
throw new ArgumentNullException("item");
|
|
if (IsReadOnly)
|
|
throw new NotSupportedException("The collection is read-only.");
|
|
|
|
if (!item.Owned)
|
|
return false;
|
|
|
|
if (_list.Remove(item))
|
|
{
|
|
item.Owned = false;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
IEnumerator IEnumerable.GetEnumerator()
|
|
{
|
|
return GetEnumerator();
|
|
}
|
|
|
|
public IEnumerator<TRestrict> GetEnumerator()
|
|
{
|
|
return _list.Where(i => i.Owned).OfType<TRestrict>().GetEnumerator();
|
|
}
|
|
|
|
public int IndexOf(TRestrict value)
|
|
{
|
|
int innerIndex = _list.IndexOf(value);
|
|
if (innerIndex == -1)
|
|
return -1;
|
|
return ToOuterIndex(innerIndex);
|
|
}
|
|
|
|
public void Insert(int index, TRestrict item)
|
|
{
|
|
if (item == null)
|
|
throw new ArgumentNullException("item");
|
|
if (IsReadOnly)
|
|
throw new NotSupportedException("The collection is read-only.");
|
|
|
|
item.Owned = true;
|
|
_list.Insert(ToInnerIndex(index), item);
|
|
}
|
|
|
|
public TRestrict this[int index]
|
|
{
|
|
get { return (TRestrict)_list[ToInnerIndex(index)]; }
|
|
set
|
|
{
|
|
int innerIndex = ToInnerIndex(index);
|
|
if (value != null)
|
|
value.Owned = true;
|
|
TTrack old = _list[innerIndex];
|
|
_list[innerIndex] = value;
|
|
|
|
if (old != null)
|
|
old.Owned = false;
|
|
}
|
|
}
|
|
|
|
public void RemoveAt(int index)
|
|
{
|
|
if (IsReadOnly)
|
|
throw new NotSupportedException("The collection is read-only");
|
|
int innerIndex = ToInnerIndex(index);
|
|
TTrack item = _list[innerIndex];
|
|
if (item.Owned)
|
|
{
|
|
_list.RemoveAt(innerIndex);
|
|
item.Owned = false;
|
|
}
|
|
}
|
|
|
|
public event NotifyCollectionChangedEventHandler CollectionChanged;
|
|
|
|
void ListOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
|
{
|
|
NotifyCollectionChangedEventHandler handler = CollectionChanged;
|
|
if (handler == null)
|
|
return;
|
|
|
|
switch (e.Action)
|
|
{
|
|
case NotifyCollectionChangedAction.Add:
|
|
if (e.NewStartingIndex == -1 || e.NewItems.Count > 1)
|
|
goto case NotifyCollectionChangedAction.Reset;
|
|
|
|
var newItem = e.NewItems[0] as TRestrict;
|
|
if (newItem == null || !newItem.Owned)
|
|
break;
|
|
|
|
int outerIndex = ToOuterIndex(e.NewStartingIndex);
|
|
handler(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, e.NewItems, outerIndex));
|
|
break;
|
|
case NotifyCollectionChangedAction.Move:
|
|
if (e.NewStartingIndex == -1 || e.OldStartingIndex == -1 || e.NewItems.Count > 1)
|
|
goto case NotifyCollectionChangedAction.Reset;
|
|
|
|
var movedItem = e.NewItems[0] as TRestrict;
|
|
if (movedItem == null || !movedItem.Owned)
|
|
break;
|
|
|
|
int outerOldIndex = ToOuterIndex(e.OldStartingIndex);
|
|
int outerNewIndex = ToOuterIndex(e.NewStartingIndex);
|
|
handler(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Move, e.NewItems, outerNewIndex, outerOldIndex));
|
|
break;
|
|
case NotifyCollectionChangedAction.Remove:
|
|
if (e.OldStartingIndex == -1 || e.OldItems.Count > 1)
|
|
goto case NotifyCollectionChangedAction.Reset;
|
|
|
|
var removedItem = e.OldItems[0] as TRestrict;
|
|
if (removedItem == null || !removedItem.Owned)
|
|
break;
|
|
|
|
int outerRemovedIndex = ToOuterIndex(e.OldStartingIndex);
|
|
var args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, removedItem, outerRemovedIndex);
|
|
handler(this, args);
|
|
break;
|
|
case NotifyCollectionChangedAction.Replace:
|
|
if (e.NewStartingIndex == -1 || e.OldStartingIndex == -1 || e.NewItems.Count > 1)
|
|
goto case NotifyCollectionChangedAction.Reset;
|
|
|
|
var newReplaceItem = e.NewItems[0] as TRestrict;
|
|
var oldReplaceItem = e.OldItems[0] as TRestrict;
|
|
|
|
if ((newReplaceItem == null || !newReplaceItem.Owned) && (oldReplaceItem == null || !oldReplaceItem.Owned))
|
|
{
|
|
break;
|
|
}
|
|
if (newReplaceItem == null || !newReplaceItem.Owned || oldReplaceItem == null || !oldReplaceItem.Owned)
|
|
{
|
|
goto case NotifyCollectionChangedAction.Reset;
|
|
}
|
|
|
|
int index = ToOuterIndex(e.NewStartingIndex);
|
|
|
|
var replaceArgs = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, newReplaceItem, oldReplaceItem, index);
|
|
handler(this, replaceArgs);
|
|
break;
|
|
case NotifyCollectionChangedAction.Reset:
|
|
handler(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
|
|
break;
|
|
default:
|
|
throw new ArgumentOutOfRangeException();
|
|
}
|
|
}
|
|
|
|
int ToInnerIndex(int outterIndex)
|
|
{
|
|
var outerIndex = 0;
|
|
int innerIndex;
|
|
for (innerIndex = 0; innerIndex < _list.Count; innerIndex++)
|
|
{
|
|
TTrack item = _list[innerIndex];
|
|
if (item is TRestrict && item.Owned)
|
|
{
|
|
if (outerIndex == outterIndex)
|
|
return innerIndex;
|
|
outerIndex++;
|
|
}
|
|
}
|
|
|
|
return innerIndex;
|
|
}
|
|
|
|
int ToOuterIndex(int innerIndex)
|
|
{
|
|
var outerIndex = 0;
|
|
for (var index = 0; index < innerIndex; index++)
|
|
{
|
|
TTrack item = _list[index];
|
|
if (item is TRestrict && item.Owned)
|
|
{
|
|
outerIndex++;
|
|
}
|
|
}
|
|
|
|
return outerIndex;
|
|
}
|
|
}
|
|
} |