File: Compatibility\Handlers\ViewHandlerDelegator.cs
Web Access
Project: src\src\Controls\src\Core\Controls.Core.csproj (Microsoft.Maui.Controls)
#if WINDOWS || IOS || ANDROID || TIZEN
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Maui.Controls.Platform;
using Microsoft.Maui.Graphics;
 
namespace Microsoft.Maui.Controls.Handlers.Compatibility
{
#if WINDOWS
	class ViewHandlerDelegator<TElement, TNativeElement>
		where TElement : VisualElement
		where TNativeElement : Microsoft.UI.Xaml.FrameworkElement
#else
	class ViewHandlerDelegator<TElement>
		where TElement : Element, IView
#endif
	{
		internal readonly IPropertyMapper _defaultMapper;
		internal IPropertyMapper _mapper;
		internal readonly CommandMapper _commandMapper;
		IPlatformViewHandler _viewHandler;
#if IOS || MACCATALYST
		TElement? _tempElement;
		WeakReference<TElement>? _element;
		public TElement? Element => _tempElement ?? _element?.GetTargetOrDefault();
#else
		TElement? _element;
		public TElement? Element => _element;
#endif
		bool _disposed;
 
		public ViewHandlerDelegator(
			IPropertyMapper mapper,
			CommandMapper commandMapper,
			IPlatformViewHandler viewHandler)
		{
			_defaultMapper = mapper;
			_mapper = _defaultMapper;
			_commandMapper = commandMapper;
			_viewHandler = viewHandler;
		}
 
		public void UpdateProperty(string property)
		{
			if (_viewHandler.VirtualView != null)
				_mapper.UpdateProperty(_viewHandler, _viewHandler.VirtualView, property);
		}
 
		public void Invoke(string command, object? args)
		{
			_commandMapper.Invoke(_viewHandler, _viewHandler.VirtualView, command, args);
		}
 
		public void DisconnectHandler()
		{
			if (Element is not TElement element)
				return;
 
			if (element.Handler == _viewHandler)
				element.Handler = null;
 
			_element = null;
 
			if (!_disposed && _viewHandler is IDisposable disposable)
			{
				disposable.Dispose();
				_disposed = true;
			}
		}
 
		public Size GetDesiredSize(double widthConstraint, double heightConstraint, Size? minimumSize = null) =>
#if WINDOWS
			VisualElementRenderer<TElement, TNativeElement>.GetDesiredSize(_viewHandler, widthConstraint, heightConstraint, minimumSize);
#else
			VisualElementRenderer<TElement>.GetDesiredSize(_viewHandler, widthConstraint, heightConstraint, minimumSize);
#endif
 
		public void PlatformArrange(Rect rect) =>
			_viewHandler.PlatformArrangeHandler(rect);
 
		public void SetVirtualView(
			Maui.IElement view,
			Action<ElementChangedEventArgs<TElement>> onElementChanged,
			bool autoPackage)
		{
#if WINDOWS
			VisualElementRenderer<TElement, TNativeElement>.SetVirtualView(view, _viewHandler, onElementChanged, ref _element, ref _mapper, _defaultMapper, autoPackage);
#elif IOS || MACCATALYST
			// _tempElement is used here, because the Element property is accessed before SetVirtualView() returns
			VisualElementRenderer<TElement>.SetVirtualView(view, _viewHandler, onElementChanged, ref _tempElement, ref _mapper, _defaultMapper, autoPackage);
			// We use _element as a WeakReference, and clear _tempElement
			_element = _tempElement is null ? null : new(_tempElement);
			_tempElement = null;
#else
			VisualElementRenderer<TElement>.SetVirtualView(view, _viewHandler, onElementChanged, ref _element, ref _mapper, _defaultMapper, autoPackage);
#endif
		}
 
		public void SetVirtualView(
			Maui.IElement view,
			Action<VisualElementChangedEventArgs> onElementChanged,
			bool autoPackage)
		{
			SetVirtualView(view, ElementChanged, false);
 
			void ElementChanged(ElementChangedEventArgs<TElement> e)
			{
				onElementChanged(new VisualElementChangedEventArgs(
					e.OldElement as VisualElement,
					e.NewElement as VisualElement));
			}
		}
	}
}
#endif