mirror of
https://gitee.com/csharpui/CPF.git
synced 2025-04-05 17:37:51 +08:00
135 lines
5.2 KiB
C#
135 lines
5.2 KiB
C#
![]() |
// Copyright (c) Microsoft Corporation.
|
|||
|
// Licensed under the MIT license.
|
|||
|
|
|||
|
using Microsoft.AspNetCore.Components;
|
|||
|
using Microsoft.AspNetCore.Components.RenderTree;
|
|||
|
using Microsoft.Extensions.Logging;
|
|||
|
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Linq;
|
|||
|
using System.Threading.Tasks;
|
|||
|
|
|||
|
namespace CPF.Razor
|
|||
|
{
|
|||
|
public abstract class NativeComponentRenderer : Renderer
|
|||
|
{
|
|||
|
private readonly Dictionary<int, NativeComponentAdapter> _componentIdToAdapter = new Dictionary<int, NativeComponentAdapter>();
|
|||
|
private ElementManager _elementManager;
|
|||
|
private readonly Dictionary<ulong, Action<ulong>> _eventRegistrations = new Dictionary<ulong, Action<ulong>>();
|
|||
|
|
|||
|
|
|||
|
public NativeComponentRenderer(IServiceProvider serviceProvider, ILoggerFactory loggerFactory)
|
|||
|
: base(serviceProvider, loggerFactory)
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
protected abstract ElementManager CreateNativeControlManager();
|
|||
|
|
|||
|
internal ElementManager ElementManager
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return _elementManager ?? (_elementManager = CreateNativeControlManager());
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public override Dispatcher Dispatcher { get; }
|
|||
|
= Dispatcher.CreateDefault();
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Creates a component of type <typeparamref name="TComponent"/> and adds it as a child of <paramref name="parent"/>.
|
|||
|
/// </summary>
|
|||
|
/// <typeparam name="TComponent"></typeparam>
|
|||
|
/// <param name="parent"></param>
|
|||
|
/// <returns></returns>
|
|||
|
public async Task AddComponent<TComponent>(IElementHandler parent) where TComponent : IComponent
|
|||
|
{
|
|||
|
await AddComponent(typeof(TComponent), parent).ConfigureAwait(false);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Creates a component of type <paramref name="componentType"/> and adds it as a child of <paramref name="parent"/>.
|
|||
|
/// </summary>
|
|||
|
/// <param name="componentType"></param>
|
|||
|
/// <param name="parent"></param>
|
|||
|
/// <returns></returns>
|
|||
|
public async Task AddComponent(Type componentType, IElementHandler parent)
|
|||
|
{
|
|||
|
await Dispatcher.InvokeAsync(async () =>
|
|||
|
{
|
|||
|
var component = InstantiateComponent(componentType);
|
|||
|
var componentId = AssignRootComponentId(component);
|
|||
|
|
|||
|
var rootAdapter = new NativeComponentAdapter(this, closestPhysicalParent: parent, knownTargetElement: parent)
|
|||
|
{
|
|||
|
Name = $"RootAdapter attached to {parent.GetType().FullName}",
|
|||
|
};
|
|||
|
|
|||
|
_componentIdToAdapter[componentId] = rootAdapter;
|
|||
|
|
|||
|
await RenderRootComponentAsync(componentId).ConfigureAwait(false);
|
|||
|
}).ConfigureAwait(false);
|
|||
|
}
|
|||
|
|
|||
|
protected override Task UpdateDisplayAsync(in RenderBatch renderBatch)
|
|||
|
{
|
|||
|
foreach (var updatedComponent in renderBatch.UpdatedComponents.Array.Take(renderBatch.UpdatedComponents.Count))
|
|||
|
{
|
|||
|
var adapter = _componentIdToAdapter[updatedComponent.ComponentId];
|
|||
|
adapter.ApplyEdits(updatedComponent.ComponentId, updatedComponent.Edits, renderBatch.ReferenceFrames, renderBatch);
|
|||
|
}
|
|||
|
|
|||
|
var numDisposedComponents = renderBatch.DisposedComponentIDs.Count;
|
|||
|
for (var i = 0; i < numDisposedComponents; i++)
|
|||
|
{
|
|||
|
var disposedComponentId = renderBatch.DisposedComponentIDs.Array[i];
|
|||
|
if (_componentIdToAdapter.TryGetValue(disposedComponentId, out var adapter))
|
|||
|
{
|
|||
|
_componentIdToAdapter.Remove(disposedComponentId);
|
|||
|
(adapter as IDisposable)?.Dispose();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
var numDisposeEventHandlers = renderBatch.DisposedEventHandlerIDs.Count;
|
|||
|
if (numDisposeEventHandlers != 0)
|
|||
|
{
|
|||
|
for (var i = 0; i < numDisposeEventHandlers; i++)
|
|||
|
{
|
|||
|
DisposeEvent(renderBatch.DisposedEventHandlerIDs.Array[i]);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return Task.CompletedTask;
|
|||
|
}
|
|||
|
|
|||
|
public void RegisterEvent(ulong eventHandlerId, Action<ulong> unregisterCallback)
|
|||
|
{
|
|||
|
if (eventHandlerId == 0)
|
|||
|
{
|
|||
|
throw new ArgumentOutOfRangeException(nameof(eventHandlerId), "Event handler ID must not be 0.");
|
|||
|
}
|
|||
|
if (unregisterCallback == null)
|
|||
|
{
|
|||
|
throw new ArgumentNullException(nameof(unregisterCallback));
|
|||
|
}
|
|||
|
_eventRegistrations.Add(eventHandlerId, unregisterCallback);
|
|||
|
}
|
|||
|
|
|||
|
private void DisposeEvent(ulong eventHandlerId)
|
|||
|
{
|
|||
|
if (!_eventRegistrations.TryGetValue(eventHandlerId, out var unregisterCallback))
|
|||
|
{
|
|||
|
throw new InvalidOperationException($"Attempting to dispose unknown event handler id '{eventHandlerId}'.");
|
|||
|
}
|
|||
|
unregisterCallback(eventHandlerId);
|
|||
|
}
|
|||
|
|
|||
|
internal NativeComponentAdapter CreateAdapterForChildComponent(IElementHandler physicalParent, int componentId)
|
|||
|
{
|
|||
|
var result = new NativeComponentAdapter(this, physicalParent);
|
|||
|
_componentIdToAdapter[componentId] = result;
|
|||
|
return result;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|