using System; using System.Collections.Specialized; using System.ComponentModel; using System.Threading.Tasks; using Windows.UI.Xaml; using Windows.UI.Xaml.Automation; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Media; namespace Xamarin.Forms.Platform.UWP { internal class TabbedPagePresenter : Windows.UI.Xaml.Controls.ContentPresenter { public TabbedPagePresenter() { Loaded += TabbedPagePresenter_Loaded; Unloaded += TabbedPagePresenter_Unloaded; SizeChanged += (s, e) => { if (ActualWidth > 0 && ActualHeight > 0) { var tab = (Page)DataContext; ((TabbedPage)tab.RealParent).ContainerArea = new Rectangle(0, 0, ActualWidth, ActualHeight); } }; } void TabbedPagePresenter_Loaded(object sender, RoutedEventArgs e) { var tab = (Page)DataContext; tab.SendAppearing(); } void TabbedPagePresenter_Unloaded(object sender, RoutedEventArgs e) { var tab = (Page)DataContext; tab.SendDisappearing(); } } public class TabbedPageRenderer : IVisualElementRenderer, ITitleProvider, IToolbarProvider { bool _disposed; bool _showTitle; VisualElementTracker _tracker; public Pivot Control { get; private set; } public TabbedPage Element { get; private set; } protected VisualElementTracker Tracker { get { return _tracker; } set { if (_tracker == value) return; if (_tracker != null) _tracker.Dispose(); _tracker = value; } } public void Dispose() { Dispose(true); } Brush ITitleProvider.BarBackgroundBrush { set { (Control as FormsPivot).ToolbarBackground = value; } } Brush ITitleProvider.BarForegroundBrush { set { (Control as FormsPivot).ToolbarForeground = value; } } bool ITitleProvider.ShowTitle { get { return _showTitle; } set { if (_showTitle == value) return; _showTitle = value; UpdateBarVisibility(); } } string ITitleProvider.Title { get { return (string)Control?.Title; } set { if (Control != null && _showTitle) Control.Title = value; } } public Task GetCommandBarAsync() { return (Control as IToolbarProvider)?.GetCommandBarAsync(); } public FrameworkElement ContainerElement { get { return Control; } } VisualElement IVisualElementRenderer.Element { get { return Element; } } public event EventHandler ElementChanged; public SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint) { var constraint = new Windows.Foundation.Size(widthConstraint, heightConstraint); double oldWidth = Control.Width; double oldHeight = Control.Height; Control.Height = double.NaN; Control.Width = double.NaN; Control.Measure(constraint); var result = new Size(Math.Ceiling(Control.DesiredSize.Width), Math.Ceiling(Control.DesiredSize.Height)); Control.Width = oldWidth; Control.Height = oldHeight; return new SizeRequest(result); } public void SetElement(VisualElement element) { if (element != null && !(element is TabbedPage)) throw new ArgumentException("Element must be a TabbedPage", "element"); TabbedPage oldElement = Element; Element = (TabbedPage)element; if (oldElement != null) { oldElement.PropertyChanged -= OnElementPropertyChanged; ((INotifyCollectionChanged)oldElement.Children).CollectionChanged -= OnPagesChanged; } if (element != null) { if (Control == null) { Control = new FormsPivot { Style = (Windows.UI.Xaml.Style)Windows.UI.Xaml.Application.Current.Resources["TabbedPageStyle"] }; Control.SelectionChanged += OnSelectionChanged; Tracker = new BackgroundTracker(Windows.UI.Xaml.Controls.Control.BackgroundProperty) { Element = (Page)element, Control = Control, Container = Control }; Control.Loaded += OnLoaded; Control.Unloaded += OnUnloaded; } Control.DataContext = Element; OnPagesChanged(Element.Children, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); UpdateCurrentPage(); ((INotifyCollectionChanged)Element.Children).CollectionChanged += OnPagesChanged; element.PropertyChanged += OnElementPropertyChanged; if (!string.IsNullOrEmpty(element.AutomationId)) Control.SetValue(AutomationProperties.AutomationIdProperty, element.AutomationId); } OnElementChanged(new VisualElementChangedEventArgs(oldElement, element)); } protected virtual void Dispose(bool disposing) { if (!disposing || _disposed) return; _disposed = true; Element?.SendDisappearing(); SetElement(null); Tracker = null; } protected void OnElementChanged(VisualElementChangedEventArgs e) { EventHandler changed = ElementChanged; if (changed != null) changed(this, e); } void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == "CurrentPage") UpdateCurrentPage(); } void OnLoaded(object sender, RoutedEventArgs args) { if (Element == null) return; Element.SendAppearing(); } void OnPagesChanged(object sender, NotifyCollectionChangedEventArgs e) { e.Apply(Element.Children, Control.Items); // Potential performance issue, UpdateLayout () is called for every page change Control.UpdateLayout(); } void OnSelectionChanged(object sender, SelectionChangedEventArgs e) { if (Element == null) return; Page page = e.AddedItems.Count > 0 ? (Page)e.AddedItems[0] : null; Page currentPage = Element.CurrentPage; if (currentPage == page) return; currentPage?.SendDisappearing(); Element.CurrentPage = page; page?.SendAppearing(); } void OnUnloaded(object sender, RoutedEventArgs args) { if (Element == null) return; Element.SendDisappearing(); } void UpdateBarVisibility() { (Control as FormsPivot).ToolbarVisibility = _showTitle ? Visibility.Visible : Visibility.Collapsed; } void UpdateCurrentPage() { Page page = Element.CurrentPage; var nav = page as NavigationPage; ((ITitleProvider)this).ShowTitle = nav != null; if (page == null) return; Control.SelectedItem = page; } } }