summaryrefslogtreecommitdiff
path: root/Xamarin.Forms.Platform.WinRT/MasterDetailPageRenderer.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Xamarin.Forms.Platform.WinRT/MasterDetailPageRenderer.cs')
-rw-r--r--Xamarin.Forms.Platform.WinRT/MasterDetailPageRenderer.cs291
1 files changed, 291 insertions, 0 deletions
diff --git a/Xamarin.Forms.Platform.WinRT/MasterDetailPageRenderer.cs b/Xamarin.Forms.Platform.WinRT/MasterDetailPageRenderer.cs
new file mode 100644
index 00000000..314cc794
--- /dev/null
+++ b/Xamarin.Forms.Platform.WinRT/MasterDetailPageRenderer.cs
@@ -0,0 +1,291 @@
+using System;
+using System.ComponentModel;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Media;
+
+namespace Xamarin.Forms.Platform.WinRT
+{
+ public class MasterDetailPageRenderer : IVisualElementRenderer, ITitleProvider
+ {
+ MasterDetailControl _container;
+
+ bool _disposed;
+ IVisualElementRenderer _masterRenderer;
+ IVisualElementRenderer _detailRenderer;
+ bool _showTitle;
+ VisualElementTracker<Page, PageControl> _tracker;
+
+ public MasterDetailPage Element { get; private set; }
+
+ protected VisualElementTracker<Page, PageControl> Tracker
+ {
+ get { return _tracker; }
+ set
+ {
+ if (_tracker == value)
+ return;
+
+ if (_tracker != null)
+ {
+ _tracker.Dispose();
+ }
+
+ _tracker = value;
+ }
+ }
+
+ bool IsPopoverFullScreen
+ {
+ get { return Device.Idiom == TargetIdiom.Phone; }
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ Brush ITitleProvider.BarBackgroundBrush
+ {
+ set { _container.ToolbarBackground = value; }
+ }
+
+ Brush ITitleProvider.BarForegroundBrush
+ {
+ set { _container.ToolbarForeground = value; }
+ }
+
+ bool ITitleProvider.ShowTitle
+ {
+ get { return _showTitle; }
+
+ set
+ {
+ if (_showTitle == value)
+ return;
+ _showTitle = value;
+ if (_showTitle)
+ _container.DetailTitleVisibility = Visibility.Visible;
+ else
+ _container.DetailTitleVisibility = Visibility.Collapsed;
+ }
+ }
+
+ string ITitleProvider.Title
+ {
+ get { return _container.Title; }
+
+ set { _container.Title = value; }
+ }
+
+ public FrameworkElement ContainerElement
+ {
+ get { return _container; }
+ }
+
+ VisualElement IVisualElementRenderer.Element
+ {
+ get { return Element; }
+ }
+
+ public event EventHandler<VisualElementChangedEventArgs> ElementChanged;
+
+ public SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint)
+ {
+ return new SizeRequest(new Size(Device.Info.ScaledScreenSize.Width, Device.Info.ScaledScreenSize.Height));
+ }
+
+ public void SetElement(VisualElement element)
+ {
+ if (element != null && !(element is MasterDetailPage))
+ throw new ArgumentException("Element must be a Page", "element");
+
+ MasterDetailPage oldElement = Element;
+ Element = (MasterDetailPage)element;
+
+ if (oldElement != null)
+ {
+ oldElement.PropertyChanged -= OnElementPropertyChanged;
+ }
+
+ if (element != null)
+ {
+ if (_container == null)
+ {
+ _container = new MasterDetailControl();
+ _container.UserClosedPopover += OnUserClosedPopover;
+ _container.SizeChanged += OnNativeSizeChanged;
+
+ Tracker = new BackgroundTracker<PageControl>(Control.BackgroundProperty) { Element = (Page)element, Container = _container };
+
+ _container.Loaded += OnLoaded;
+ _container.Unloaded += OnUnloaded;
+ }
+
+ element.PropertyChanged += OnElementPropertyChanged;
+ UpdateBehavior();
+ SetMaster(Element.Master);
+ SetDetail(Element.Detail);
+ UpdateIsPresented();
+ }
+
+ OnElementChanged(new VisualElementChangedEventArgs(oldElement, element));
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!disposing || _disposed)
+ return;
+
+ _disposed = true;
+
+ SetElement(null);
+ }
+
+ protected void OnElementChanged(VisualElementChangedEventArgs e)
+ {
+ EventHandler<VisualElementChangedEventArgs> changed = ElementChanged;
+ if (changed != null)
+ changed(this, e);
+ }
+
+ protected virtual void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName == "Master")
+ SetMaster(Element.Master);
+ else if (e.PropertyName == "Detail")
+ SetDetail(Element.Detail);
+ else if (e.PropertyName == MasterDetailPage.IsPresentedProperty.PropertyName)
+ UpdateIsPresented();
+ else if (e.PropertyName == MasterDetailPage.MasterBehaviorProperty.PropertyName)
+ UpdateBehavior();
+ else if (e.PropertyName == Page.TitleProperty.PropertyName)
+ UpdateTitle();
+ }
+
+ bool GetIsMasterAPopover()
+ {
+ // TODO: Support tablet being shrunk to a very small size
+ return !Element.ShouldShowSplitMode;
+ }
+
+ void OnLoaded(object sender, RoutedEventArgs args)
+ {
+ if (Element == null)
+ return;
+
+ Element.SendAppearing();
+ }
+
+ void OnNativeSizeChanged(object sender, SizeChangedEventArgs e)
+ {
+ UpdateBounds(e.NewSize);
+ }
+
+ void OnUnloaded(object sender, RoutedEventArgs args)
+ {
+ if (Element == null)
+ return;
+
+ Element.SendDisappearing();
+ }
+
+ void OnUserClosedPopover(object sender, EventArgs e)
+ {
+ if (Element != null)
+ ((IElementController)Element).SetValueFromRenderer(MasterDetailPage.IsPresentedProperty, false);
+ }
+
+ void SetDetail(Page detailPage)
+ {
+ ((ITitleProvider)this).ShowTitle = detailPage is NavigationPage;
+
+ if (_detailRenderer != null)
+ {
+ FrameworkElement native = _detailRenderer.ContainerElement;
+ _container.DetailContent = null;
+ _detailRenderer = null;
+ }
+
+ if (detailPage == null)
+ return;
+
+ _detailRenderer = detailPage.GetOrCreateRenderer();
+ _container.DetailContent = _detailRenderer.ContainerElement;
+ UpdateTitle();
+ }
+
+ void SetMaster(Page masterPage)
+ {
+ if (_masterRenderer != null)
+ {
+ FrameworkElement native = _masterRenderer.ContainerElement;
+ _container.MasterContent = null;
+ _masterRenderer = null;
+ }
+
+ if (masterPage == null)
+ return;
+
+ _masterRenderer = masterPage.GetOrCreateRenderer();
+ _container.MasterContent = _masterRenderer.ContainerElement;
+ }
+
+ void UpdateBehavior()
+ {
+ string key = GetIsMasterAPopover() ? "MasterDetailPopup" : "MasterDetailSplit";
+ _container.Template = (Windows.UI.Xaml.Controls.ControlTemplate)Windows.UI.Xaml.Application.Current.Resources[key];
+ }
+
+ void UpdateBounds(bool isPresented)
+ {
+ UpdateBounds(new Windows.Foundation.Size(_container.ActualWidth, _container.ActualHeight), isPresented);
+ }
+
+ void UpdateBounds(Windows.Foundation.Size constraint)
+ {
+ UpdateBounds(constraint, Element.IsPresented);
+ }
+
+ void UpdateBounds(Windows.Foundation.Size constraint, bool isPresented)
+ {
+ if (constraint.Width <= 0 || constraint.Height <= 0)
+ return;
+
+ bool isPopover = GetIsMasterAPopover();
+ double masterWidth = 0;
+ if (isPresented || isPopover)
+ {
+ if (isPopover && IsPopoverFullScreen)
+ masterWidth = constraint.Width;
+ else
+ masterWidth = constraint.Width * .3;
+ }
+
+ double detailWidth = constraint.Width;
+ if (!isPopover)
+ detailWidth -= masterWidth;
+
+ Element.MasterBounds = new Rectangle(0, 0, masterWidth, constraint.Height);
+ Element.DetailBounds = new Rectangle(0, 0, detailWidth, constraint.Height);
+ }
+
+ void UpdateIsPresented()
+ {
+ UpdateBehavior();
+
+ bool isPresented = !GetIsMasterAPopover() || Element.IsPresented;
+ _container.IsMasterVisible = isPresented;
+
+ UpdateBounds(isPresented);
+ }
+
+ void UpdateTitle()
+ {
+ if (Element?.Detail == null)
+ return;
+
+ ((ITitleProvider)this).Title = (Element.Detail as NavigationPage)?.CurrentPage?.Title ?? Element.Title ?? Element?.Title;
+ }
+ }
+} \ No newline at end of file