| File: Handlers\Element\ElementHandler.cs | Web Access |
| Project: src\src\Core\src\Core.csproj (Microsoft.Maui) |
using System; namespace Microsoft.Maui.Handlers { public abstract partial class ElementHandler : IElementHandler { public static IPropertyMapper<IElement, IElementHandler> ElementMapper = new PropertyMapper<IElement, IElementHandler>() { }; public static CommandMapper<IElement, IElementHandler> ElementCommandMapper = new CommandMapper<IElement, IElementHandler>() { }; internal readonly IPropertyMapper _defaultMapper; internal readonly CommandMapper? _commandMapper; internal IPropertyMapper _mapper; protected ElementHandler(IPropertyMapper mapper, CommandMapper? commandMapper = null) { _ = mapper ?? throw new ArgumentNullException(nameof(mapper)); _defaultMapper = mapper; _mapper = _defaultMapper; _commandMapper = commandMapper; } public IMauiContext? MauiContext { get; private set; } public IServiceProvider? Services => MauiContext?.Services; public object? PlatformView { get; private protected set; } public IElement? VirtualView { get; private protected set; } public virtual void SetMauiContext(IMauiContext mauiContext) => MauiContext = mauiContext; public virtual void SetVirtualView(IElement view) { _ = view ?? throw new ArgumentNullException(nameof(view)); if (VirtualView == view) return; var oldVirtualView = VirtualView; bool setupPlatformView = oldVirtualView == null; VirtualView = view; PlatformView ??= CreatePlatformElement(); if (VirtualView.Handler != this) VirtualView.Handler = this; // We set the previous virtual view to null after setting it on the incoming virtual view. // This makes it easier for the incoming virtual view to have influence // on how the exchange of handlers happens. // We will just set the handler to null ourselves as a last resort cleanup if (oldVirtualView?.Handler != null) oldVirtualView.Handler = null; if (setupPlatformView) { ConnectHandler(PlatformView); } _mapper = _defaultMapper; if (VirtualView is IPropertyMapperView imv) { var map = imv.GetPropertyMapperOverrides(); if (map is not null) { map.Chained = new[] { _defaultMapper }; _mapper = map; } } _mapper.UpdateProperties(this, VirtualView); } public virtual void UpdateValue(string property) { if (VirtualView == null) return; _mapper?.UpdateProperty(this, VirtualView, property); } public virtual void Invoke(string command, object? args) { if (VirtualView == null) return; _commandMapper?.Invoke(this, VirtualView, command, args); } private protected abstract object OnCreatePlatformElement(); object CreatePlatformElement() => OnCreatePlatformElement(); private protected abstract void OnConnectHandler(object platformView); void ConnectHandler(object platformView) => OnConnectHandler(platformView); private protected abstract void OnDisconnectHandler(object platformView); void DisconnectHandler(object platformView) { OnDisconnectHandler(platformView); // VirtualView has already been changed over to a new handler if (VirtualView != null && VirtualView.Handler == this) VirtualView.Handler = null; VirtualView = null; } void IElementHandler.DisconnectHandler() { if (PlatformView != null && VirtualView != null) { // We set the PlatformView to null so no one outside of this handler tries to access // PlatformView. PlatformView access should be isolated to the instance passed into // DisconnectHandler var oldPlatformView = PlatformView; PlatformView = null; DisconnectHandler(oldPlatformView); } } } }