using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; using System.Linq; namespace Xamarin.Forms { internal class ToolbarTracker { int _masterDetails; Page _target; public IEnumerable AdditionalTargets { get; set; } public bool HaveMasterDetail { get { return _masterDetails > 0; } } public bool SeparateMasterDetail { get; set; } public Page Target { get { return _target; } set { if (_target == value) return; UntrackTarget(_target); _target = value; if (_target != null) TrackTarget(_target); EmitCollectionChanged(); } } public IEnumerable ToolbarItems { get { if (Target == null) return Enumerable.Empty(); IEnumerable items = GetCurrentToolbarItems(Target); if (AdditionalTargets != null) items = items.Concat(AdditionalTargets.SelectMany(t => t.ToolbarItems)); return items.OrderBy(ti => ti.Priority); } } public event EventHandler CollectionChanged; void EmitCollectionChanged() { if (CollectionChanged != null) CollectionChanged(this, EventArgs.Empty); } IEnumerable GetCurrentToolbarItems(Page page) { var result = new List(); result.AddRange(page.ToolbarItems); if (page is MasterDetailPage) { var masterDetail = (MasterDetailPage)page; if (SeparateMasterDetail) { if (masterDetail.IsPresented) { if (masterDetail.Master != null) result.AddRange(GetCurrentToolbarItems(masterDetail.Master)); } else { if (masterDetail.Detail != null) result.AddRange(GetCurrentToolbarItems(masterDetail.Detail)); } } else { if (masterDetail.Master != null) result.AddRange(GetCurrentToolbarItems(masterDetail.Master)); if (masterDetail.Detail != null) result.AddRange(GetCurrentToolbarItems(masterDetail.Detail)); } } else if (page is IPageContainer) { var container = (IPageContainer)page; if (container.CurrentPage != null) result.AddRange(GetCurrentToolbarItems(container.CurrentPage)); } return result; } void OnChildAdded(object sender, ElementEventArgs eventArgs) { var page = eventArgs.Element as Page; if (page == null) return; RegisterChildPage(page); } void OnChildRemoved(object sender, ElementEventArgs eventArgs) { var page = eventArgs.Element as Page; if (page == null) return; UnregisterChildPage(page); } void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs notifyCollectionChangedEventArgs) { EmitCollectionChanged(); } void OnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs) { if (propertyChangedEventArgs.PropertyName == NavigationPage.CurrentPageProperty.PropertyName || propertyChangedEventArgs.PropertyName == MasterDetailPage.IsPresentedProperty.PropertyName || propertyChangedEventArgs.PropertyName == "Detail" || propertyChangedEventArgs.PropertyName == "Master") { EmitCollectionChanged(); } } void RegisterChildPage(Page page) { if (page is MasterDetailPage) _masterDetails++; ((ObservableCollection)page.ToolbarItems).CollectionChanged += OnCollectionChanged; page.PropertyChanged += OnPropertyChanged; } void TrackTarget(Page page) { if (page == null) return; if (page is MasterDetailPage) _masterDetails++; ((ObservableCollection)page.ToolbarItems).CollectionChanged += OnCollectionChanged; page.Descendants().OfType().ForEach(RegisterChildPage); page.DescendantAdded += OnChildAdded; page.DescendantRemoved += OnChildRemoved; page.PropertyChanged += OnPropertyChanged; } void UnregisterChildPage(Page page) { if (page is MasterDetailPage) _masterDetails--; ((ObservableCollection)page.ToolbarItems).CollectionChanged -= OnCollectionChanged; page.PropertyChanged -= OnPropertyChanged; } void UntrackTarget(Page page) { if (page == null) return; if (page is MasterDetailPage) _masterDetails--; ((ObservableCollection)page.ToolbarItems).CollectionChanged -= OnCollectionChanged; page.Descendants().OfType().ForEach(UnregisterChildPage); page.DescendantAdded -= OnChildAdded; page.DescendantRemoved -= OnChildRemoved; page.PropertyChanged -= OnPropertyChanged; } } }