diff options
author | Jason Smith <jason.smith@xamarin.com> | 2016-04-24 12:25:26 -0400 |
---|---|---|
committer | Rui Marinho <me@ruimarinho.net> | 2016-04-24 12:25:26 -0400 |
commit | 5907152c50ee2c658b266f2804e6b383bb15a6f1 (patch) | |
tree | 9beb907623359723456c5c03b08922bebc4f41f3 /Xamarin.Forms.Pages/CompoundCollection.cs | |
parent | feac1ba3ed6df5e27b3fa2076bd15c190cbacd1c (diff) | |
download | xamarin-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.cs | 223 |
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 |