using System; using AppKit; using RectangleF = CoreGraphics.CGRect; namespace Xamarin.Forms.Platform.MacOS { internal class ViewCellNSView : CellNSView { public ViewCellNSView() : base(NSTableViewCellStyle.Empty) { } WeakReference _rendererRef; ViewCell _viewCell; public override Element Element => ViewCell; public ViewCell ViewCell { get { return _viewCell; } set { if (_viewCell == value) return; UpdateCell(value); } } public override void Layout() { LayoutSubviews(); base.Layout(); } protected override void Dispose(bool disposing) { if (disposing) { IVisualElementRenderer renderer; if (_rendererRef != null && _rendererRef.TryGetTarget(out renderer) && renderer.Element != null) { Platform.DisposeModelAndChildrenRenderers(renderer.Element); _rendererRef = null; } } base.Dispose(disposing); } void LayoutSubviews() { var contentFrame = Frame; var view = ViewCell.View; Xamarin.Forms.Layout.LayoutChildIntoBoundingRegion(view, contentFrame.ToRectangle()); if (_rendererRef == null) return; IVisualElementRenderer renderer; if (_rendererRef.TryGetTarget(out renderer)) renderer.NativeView.Frame = view.Bounds.ToRectangleF(); } IVisualElementRenderer GetNewRenderer() { var newRenderer = Platform.CreateRenderer(_viewCell.View); _rendererRef = new WeakReference(newRenderer); AddSubview(newRenderer.NativeView); return newRenderer; } void UpdateCell(ViewCell cell) { if (_viewCell != null) Device.BeginInvokeOnMainThread(_viewCell.SendDisappearing); _viewCell = cell; Device.BeginInvokeOnMainThread(_viewCell.SendAppearing); IVisualElementRenderer renderer; if (_rendererRef == null || !_rendererRef.TryGetTarget(out renderer)) renderer = GetNewRenderer(); else { if (renderer.Element != null && renderer == Platform.GetRenderer(renderer.Element)) renderer.Element.ClearValue(Platform.RendererProperty); var type = Internals.Registrar.Registered.GetHandlerType(_viewCell.View.GetType()); if (renderer.GetType() == type || (renderer is DefaultRenderer && type == null)) renderer.SetElement(_viewCell.View); else { //when cells are getting reused the element could be already set to another cell //so we should dispose based on the renderer and not the renderer.Element Platform.DisposeRendererAndChildren(renderer); renderer = GetNewRenderer(); } } Platform.SetRenderer(_viewCell.View, renderer); } } }