summaryrefslogtreecommitdiff
path: root/Xamarin.Forms.Platform.MacOS/Renderers/MasterDetailPageRenderer.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Xamarin.Forms.Platform.MacOS/Renderers/MasterDetailPageRenderer.cs')
-rw-r--r--Xamarin.Forms.Platform.MacOS/Renderers/MasterDetailPageRenderer.cs204
1 files changed, 204 insertions, 0 deletions
diff --git a/Xamarin.Forms.Platform.MacOS/Renderers/MasterDetailPageRenderer.cs b/Xamarin.Forms.Platform.MacOS/Renderers/MasterDetailPageRenderer.cs
new file mode 100644
index 00000000..8d2fd551
--- /dev/null
+++ b/Xamarin.Forms.Platform.MacOS/Renderers/MasterDetailPageRenderer.cs
@@ -0,0 +1,204 @@
+using System;
+using System.ComponentModel;
+using System.Linq;
+using AppKit;
+using CoreGraphics;
+
+namespace Xamarin.Forms.Platform.MacOS
+{
+ public class MasterDetailPageRenderer : NSSplitViewController, IVisualElementRenderer, IEffectControlProvider
+ {
+ bool _disposed;
+ EventTracker _events;
+ VisualElementTracker _tracker;
+ MasterDetailPage _masterDetailPage;
+
+ IPageController PageController => Element as IPageController;
+
+ void IEffectControlProvider.RegisterEffect(Effect effect)
+ {
+ var platformEffect = effect as PlatformEffect;
+ if (platformEffect != null)
+ platformEffect.Container = View;
+ }
+
+ protected MasterDetailPage MasterDetailPage => _masterDetailPage ?? (_masterDetailPage = (MasterDetailPage)Element);
+
+ protected override void Dispose(bool disposing)
+ {
+ if (!_disposed && disposing)
+ {
+ PageController?.SendDisappearing();
+
+ if (Element != null)
+ {
+ Element.PropertyChanged -= HandlePropertyChanged;
+ Element = null;
+ }
+
+ ClearControllers();
+
+ _tracker?.Dispose();
+ _tracker = null;
+ _events?.Dispose();
+ _events = null;
+
+ _disposed = true;
+ }
+ base.Dispose(disposing);
+ }
+
+ public NSViewController ViewController => this;
+
+ public NSView NativeView => View;
+
+ public VisualElement Element { get; private set; }
+
+ public event EventHandler<VisualElementChangedEventArgs> ElementChanged;
+
+ public SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint)
+ {
+ return NativeView.GetSizeRequest(widthConstraint, heightConstraint);
+ }
+
+ public void SetElement(VisualElement element)
+ {
+ var oldElement = Element;
+ Element = element;
+
+ UpdateControllers();
+
+ OnElementChanged(new VisualElementChangedEventArgs(oldElement, element));
+
+ EffectUtilities.RegisterEffectControlProvider(this, oldElement, element);
+ }
+
+ public void SetElementSize(Size size)
+ {
+ Element.Layout(new Rectangle(Element.X, Element.Y, size.Width, size.Height));
+ UpdateChildrenLayout();
+ }
+
+ protected virtual void OnElementChanged(VisualElementChangedEventArgs e)
+ {
+ if (e.OldElement != null)
+ e.OldElement.PropertyChanged -= HandlePropertyChanged;
+
+ if (e.NewElement != null)
+ e.NewElement.PropertyChanged += HandlePropertyChanged;
+
+ ElementChanged?.Invoke(this, e);
+ }
+
+ protected virtual double MasterWidthPercentage => 0.3;
+
+ public override void ViewWillAppear()
+ {
+ UpdateBackground();
+ _tracker = new VisualElementTracker(this);
+ _events = new EventTracker(this);
+ _events.LoadEvents(NativeView);
+ UpdateChildrenLayout();
+
+ base.ViewWillAppear();
+ }
+
+ public override CGRect GetEffectiveRect(NSSplitView splitView, CGRect proposedEffectiveRect, CGRect drawnRect,
+ nint dividerIndex)
+ {
+ return CGRect.Empty;
+ }
+
+ void UpdateChildrenLayout()
+ {
+ if (View.Frame.Width == -1)
+ return;
+ var width = View.Frame.Width;
+ var masterWidth = MasterWidthPercentage * width;
+ if (SplitViewItems.Length > 0)
+ SplitViewItems[0].MaximumThickness = SplitViewItems[0].MinimumThickness = (nfloat)masterWidth;
+ }
+
+ void HandlePropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ if (_tracker == null)
+ return;
+
+ if (e.PropertyName == "Master" || e.PropertyName == "Detail")
+ UpdateControllers();
+ }
+
+ void UpdateControllers()
+ {
+ ClearControllers();
+
+ if (Platform.GetRenderer(MasterDetailPage.Master) == null)
+ Platform.SetRenderer(MasterDetailPage.Master, Platform.CreateRenderer(MasterDetailPage.Master));
+ if (Platform.GetRenderer(MasterDetailPage.Detail) == null)
+ Platform.SetRenderer(MasterDetailPage.Detail, Platform.CreateRenderer(MasterDetailPage.Detail));
+
+ AddSplitViewItem(new NSSplitViewItem
+ {
+ ViewController = new ViewControllerWrapper(Platform.GetRenderer(MasterDetailPage.Master))
+ });
+ AddSplitViewItem(new NSSplitViewItem
+ {
+ ViewController = new ViewControllerWrapper(Platform.GetRenderer(MasterDetailPage.Detail))
+ });
+
+ UpdateChildrenLayout();
+ }
+
+ void ClearControllers()
+ {
+ while (SplitViewItems.Length > 0)
+ {
+ var splitItem = SplitViewItems.Last();
+ var childVisualRenderer = splitItem.ViewController as ViewControllerWrapper;
+ RemoveSplitViewItem(splitItem);
+ IVisualElementRenderer render = null;
+ if (childVisualRenderer.RendererWeakRef.TryGetTarget(out render))
+ {
+ render.Dispose();
+ }
+ childVisualRenderer.Dispose();
+ childVisualRenderer = null;
+ }
+ }
+
+ //TODO: Implement Background color on MDP
+ void UpdateBackground()
+ {
+ }
+
+ sealed class ViewControllerWrapper : NSViewController
+ {
+ internal WeakReference<IVisualElementRenderer> RendererWeakRef;
+
+ public ViewControllerWrapper(IVisualElementRenderer renderer)
+ {
+ RendererWeakRef = new WeakReference<IVisualElementRenderer>(renderer);
+ View = new NSView { WantsLayer = true };
+ AddChildViewController(renderer.ViewController);
+ View.AddSubview(renderer.NativeView);
+ }
+
+ public override void ViewWillLayout()
+ {
+ IVisualElementRenderer renderer;
+ if (RendererWeakRef.TryGetTarget(out renderer))
+ renderer?.Element?.Layout(new Rectangle(0, 0, View.Bounds.Width, View.Bounds.Height));
+ base.ViewWillLayout();
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && RendererWeakRef != null)
+ {
+ RendererWeakRef = null;
+ }
+ base.Dispose(disposing);
+ }
+ }
+ }
+} \ No newline at end of file