summaryrefslogtreecommitdiff
path: root/Xamarin.Forms.Pages/CompoundCollection.cs
diff options
context:
space:
mode:
authorJason Smith <jason.smith@xamarin.com>2016-04-24 12:25:26 -0400
committerRui Marinho <me@ruimarinho.net>2016-04-24 12:25:26 -0400
commit5907152c50ee2c658b266f2804e6b383bb15a6f1 (patch)
tree9beb907623359723456c5c03b08922bebc4f41f3 /Xamarin.Forms.Pages/CompoundCollection.cs
parentfeac1ba3ed6df5e27b3fa2076bd15c190cbacd1c (diff)
downloadxamarin-forms-5907152c50ee2c658b266f2804e6b383bb15a6f1.tar.gz
xamarin-forms-5907152c50ee2c658b266f2804e6b383bb15a6f1.tar.bz2
xamarin-forms-5907152c50ee2c658b266f2804e6b383bb15a6f1.zip
Evolve feature branch (#117)
* Initial import of evolve features * [Android] Add Xamarin.Forms.Platform.Android.AppLinks project * [iOS] Fix issues with c# 6 features on iOS AppLinks * Added naive stanza to update-docs-windows.bat to produce Pages docs. Not tested. (#69) * Update packages * Add AppLinks android nuspec and fix linker issues * Fix build * Fix nusepc * Fix nuspec * Update android support nugets to 23.2.1 * Update Xamarin.UITest * Add CardView * [iOS] Fix app link for CoreSpotlight * [Android] Update AppLinks android support libs * Add Newtonsoft.Json dependency to nuspec * Fix NRE when setting ControlTemplate to null * Move to ModernHttpClient for download * Try fix build * Preserve android app links * Fix margin issue * General coding and simple fixes
Diffstat (limited to 'Xamarin.Forms.Pages/CompoundCollection.cs')
-rw-r--r--Xamarin.Forms.Pages/CompoundCollection.cs223
1 files changed, 223 insertions, 0 deletions
diff --git a/Xamarin.Forms.Pages/CompoundCollection.cs b/Xamarin.Forms.Pages/CompoundCollection.cs
new file mode 100644
index 00000000..6dbf502b
--- /dev/null
+++ b/Xamarin.Forms.Pages/CompoundCollection.cs
@@ -0,0 +1,223 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Collections.Specialized;
+using System.Linq;
+
+namespace Xamarin.Forms.Pages
+{
+ public class CompoundCollection : Element, IList, INotifyCollectionChanged
+ {
+ public static readonly BindableProperty MainListProperty = BindableProperty.Create(nameof(MainList), typeof(IReadOnlyList<object>), typeof(CompoundCollection), default(IReadOnlyList<object>),
+ propertyChanged: OnMainListPropertyChanged);
+
+ readonly ObservableCollection<object> _appendList = new ObservableCollection<object>();
+
+ readonly ObservableCollection<object> _prependList = new ObservableCollection<object>();
+
+ public CompoundCollection()
+ {
+ _prependList.CollectionChanged += OnPrependCollectionChanged;
+ _appendList.CollectionChanged += OnAppendCollectionChanged;
+ }
+
+ public IList AppendList => _appendList;
+
+ public IReadOnlyList<object> MainList
+ {
+ get { return (IReadOnlyList<object>)GetValue(MainListProperty); }
+ set { SetValue(MainListProperty, value); }
+ }
+
+ public IList PrependList => _prependList;
+
+ public void CopyTo(Array array, int index)
+ {
+ throw new NotSupportedException();
+ }
+
+ public int Count => AppendList.Count + PrependList.Count + (MainList?.Count ?? 0);
+
+ public bool IsSynchronized => false;
+
+ public object SyncRoot => null;
+
+ public IEnumerator GetEnumerator()
+ {
+ foreach (object item in PrependList)
+ yield return item;
+ foreach (object item in MainList)
+ yield return item;
+ foreach (object item in AppendList)
+ yield return item;
+ }
+
+ public int Add(object value)
+ {
+ throw new NotSupportedException();
+ }
+
+ public void Clear()
+ {
+ throw new NotSupportedException();
+ }
+
+ public bool Contains(object value)
+ {
+ IReadOnlyList<object> mainList = MainList;
+ bool masterContains;
+ var masterList = mainList as IList;
+ if (masterList != null)
+ {
+ masterContains = masterList.Contains(value);
+ }
+ else
+ {
+ masterContains = mainList.Contains(value);
+ }
+ return masterContains || PrependList.Contains(value) || AppendList.Contains(value);
+ }
+
+ public int IndexOf(object value)
+ {
+ int result;
+ result = PrependList.IndexOf(value);
+ if (result >= 0)
+ return result;
+ result = MainList.IndexOf(value);
+ if (result >= 0)
+ return result + PrependList.Count;
+
+ result = AppendList.IndexOf(value);
+ if (result >= 0)
+ return result + PrependList.Count + MainList.Count;
+ return -1;
+ }
+
+ public void Insert(int index, object value)
+ {
+ throw new NotSupportedException();
+ }
+
+ public bool IsFixedSize => false;
+
+ public bool IsReadOnly => true;
+
+ public object this[int index]
+ {
+ get
+ {
+ IReadOnlyList<object> mainList = MainList;
+ int prependSize = PrependList.Count;
+ if (index < prependSize)
+ return PrependList[index];
+ index -= prependSize;
+
+ if (mainList != null)
+ {
+ if (index < mainList.Count)
+ return mainList[index];
+ index -= mainList.Count;
+ }
+
+ if (index >= AppendList.Count)
+ throw new IndexOutOfRangeException();
+ return AppendList[index];
+ }
+ set { throw new NotSupportedException(); }
+ }
+
+ public void Remove(object value)
+ {
+ throw new NotSupportedException();
+ }
+
+ public void RemoveAt(int index)
+ {
+ throw new NotSupportedException();
+ }
+
+ public event NotifyCollectionChangedEventHandler CollectionChanged;
+
+ void OnAppendCollectionChanged(object sender, NotifyCollectionChangedEventArgs args)
+ {
+ int offset = _prependList.Count + (MainList?.Count ?? 0);
+ // here we just need to calculate the offset for the index, everything else is the same
+ switch (args.Action)
+ {
+ case NotifyCollectionChangedAction.Add:
+ OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, args.NewItems, offset + args.NewStartingIndex));
+ break;
+ case NotifyCollectionChangedAction.Move:
+ OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Move, args.OldItems, offset + args.NewStartingIndex, offset + args.OldStartingIndex));
+ break;
+ case NotifyCollectionChangedAction.Remove:
+ OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, args.OldItems, offset + args.OldStartingIndex));
+ break;
+ case NotifyCollectionChangedAction.Replace:
+ OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, args.NewItems, args.OldItems, offset + args.OldStartingIndex));
+ break;
+ case NotifyCollectionChangedAction.Reset:
+ OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
+ break;
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+ }
+
+ 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();
+ }
+ }
+
+ static void OnMainListPropertyChanged(BindableObject bindable, object oldValue, object newValue)
+ {
+ var self = (CompoundCollection)bindable;
+ var observable = oldValue as INotifyCollectionChanged;
+ if (observable != null)
+ observable.CollectionChanged -= self.OnMainCollectionChanged;
+ observable = newValue as INotifyCollectionChanged;
+ if (observable != null)
+ observable.CollectionChanged += self.OnMainCollectionChanged;
+ self.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
+ }
+
+ void OnPrependCollectionChanged(object sender, NotifyCollectionChangedEventArgs args)
+ {
+ // this can basically be a passthrough as prepend has no masking and identical indexing
+ OnCollectionChanged(args);
+ }
+
+ int PublicIndexFromMainIndex(int index)
+ {
+ return PrependList.Count + index;
+ }
+ }
+} \ No newline at end of file