From 8aa05cb447858b03e999b67b3d15afe4994c6a34 Mon Sep 17 00:00:00 2001 From: Adolfo Marinucci Date: Mon, 23 Dec 2024 13:15:24 +0100 Subject: [PATCH] fully aot --- .../MauiReactor.TestAot.csproj | 34 +- .../MauiReactor.Blazor.csproj | 12 +- .../MauiReactor.Canvas.csproj | 4 +- src/MauiReactor/Component.cs | 326 ++++++++++-------- src/MauiReactor/MauiReactor.csproj | 4 +- src/MauiReactor/Parameters/Parameter.cs | 110 +++--- src/MauiReactor/Shell.partial.cs | 26 +- 7 files changed, 288 insertions(+), 228 deletions(-) diff --git a/samples/MauiReactor.TestAot/MauiReactor.TestAot.csproj b/samples/MauiReactor.TestAot/MauiReactor.TestAot.csproj index 0d499b85..7edbc85c 100644 --- a/samples/MauiReactor.TestAot/MauiReactor.TestAot.csproj +++ b/samples/MauiReactor.TestAot/MauiReactor.TestAot.csproj @@ -20,15 +20,15 @@ enable enable - - true + + true - - true - true + + true + true - + MauiReactor.TestAot @@ -73,17 +73,17 @@ - - - - - - - - - - - + + + + + + + + + + + diff --git a/src/MauiReactor.Blazor/MauiReactor.Blazor.csproj b/src/MauiReactor.Blazor/MauiReactor.Blazor.csproj index 41844537..5ad8bf97 100644 --- a/src/MauiReactor.Blazor/MauiReactor.Blazor.csproj +++ b/src/MauiReactor.Blazor/MauiReactor.Blazor.csproj @@ -12,12 +12,12 @@ true RS1036,NU1903,NU1902,NU1901 - 14.2 - 14.0 - 21.0 - 10.0.17763.0 - 10.0.17763.0 - 6.5 + 15.0 + 15.0 + 21.0 + 10.0.17763.0 + 10.0.17763.0 + 6.5 0.0.1 diff --git a/src/MauiReactor.Canvas/MauiReactor.Canvas.csproj b/src/MauiReactor.Canvas/MauiReactor.Canvas.csproj index 1711189f..066ba0f1 100644 --- a/src/MauiReactor.Canvas/MauiReactor.Canvas.csproj +++ b/src/MauiReactor.Canvas/MauiReactor.Canvas.csproj @@ -12,8 +12,8 @@ true RS1036,NU1903,NU1902,NU1901 - 14.2 - 14.0 + 15.0 + 15.0 21.0 10.0.17763.0 10.0.17763.0 diff --git a/src/MauiReactor/Component.cs b/src/MauiReactor/Component.cs index 7c14f737..0824e95c 100644 --- a/src/MauiReactor/Component.cs +++ b/src/MauiReactor/Component.cs @@ -13,7 +13,7 @@ public abstract partial class Component : VisualNode, IEnumerable, I private readonly List _children = []; private readonly Dictionary _attachedProperties = []; - + public abstract VisualNode Render(); public void SetProperty(BindableProperty property, object? value) @@ -95,12 +95,12 @@ protected sealed override void OnUpdate() protected override void MergeWith(VisualNode newNode) { if (newNode.GetType().FullName == GetType().FullName && _isMounted) - { - OnMigrating(newNode); + { + OnMigrating(newNode); ((Component)newNode)._isMounted = true; ((Component)newNode)._nativeControl = _nativeControl; _nativeControl = null; - ((Component)newNode).OnPropsChanged(); + ((Component)newNode).OnPropsChanged(); ((Component)newNode).OnMountedOrPropsChanged(); OnMigrated(newNode); @@ -142,12 +142,12 @@ protected virtual void OnWillUnmount() } protected virtual void OnPropsChanged() - { + { } - protected virtual void OnMountedOrPropsChanged() - { - + protected virtual void OnMountedOrPropsChanged() + { + } public INavigation Navigation @@ -156,8 +156,8 @@ public INavigation Navigation public bool IsNavigationAvailable => (_containerPage ??= ((IVisualNode)this).GetContainerPage())?.Navigation != null || NavigationProvider.Navigation != null; - private Microsoft.Maui.Controls.Page? _containerPage; - + private Microsoft.Maui.Controls.Page? _containerPage; + public Microsoft.Maui.Controls.Page ContainerPage { get @@ -166,61 +166,61 @@ public Microsoft.Maui.Controls.Page ContainerPage return _containerPage ?? throw new InvalidCastException ("ContainerPage as been disconnected from the component, check its availability with the property IsContainerPageAvailable"); } } - - public bool IsContainerPageAvailable - => (_containerPage ??= ((IVisualNode)this).GetContainerPage()) != null; + + public bool IsContainerPageAvailable + => (_containerPage ??= ((IVisualNode)this).GetContainerPage()) != null; public static IServiceProvider Services - => ServiceCollectionProvider.ServiceProvider ?? throw new InvalidOperationException("Services not available"); - - internal void InvalidateComponent() => Invalidate(); - - protected new void Invalidate() - { - if (!_invalidated) - { - if (Application.Current != null) - { - if (Application.Current.Dispatcher.IsDispatchRequired) - { - _invalidated = true; - Application.Current.Dispatcher.Dispatch(base.Invalidate); - } - else - base.Invalidate(); - } - else - { - base.Invalidate(); - } - } + => ServiceCollectionProvider.ServiceProvider ?? throw new InvalidOperationException("Services not available"); + + internal void InvalidateComponent() => Invalidate(); + + protected new void Invalidate() + { + if (!_invalidated) + { + if (Application.Current != null) + { + if (Application.Current.Dispatcher.IsDispatchRequired) + { + _invalidated = true; + Application.Current.Dispatcher.Dispatch(base.Invalidate); + } + else + base.Invalidate(); + } + else + { + base.Invalidate(); + } + } } protected IParameter CreateParameter(string? name = null) where T : new() { - var parameterContext = new ParameterContext(this); + var parameterContext = new ParameterContext(this); return parameterContext.Create(name); } public IParameter GetParameter(string? name = null) where T : new() - { - var parameterContext = new ParameterContext(this); - return parameterContext.Get(name) ?? throw new InvalidOperationException($"Unable to find parameter with name '{name ?? typeof(T).FullName}'"); - } + { + var parameterContext = new ParameterContext(this); + return parameterContext.Get(name) ?? throw new InvalidOperationException($"Unable to find parameter with name '{name ?? typeof(T).FullName}'"); + } protected IParameter GetOrCreateParameter(string? name = null) where T : new() { - var parameterContext = new ParameterContext(this); + var parameterContext = new ParameterContext(this); return parameterContext.Get(name) ?? parameterContext.Create(name); - } - - //public static VisualNode Render(Func renderFunc) - //{ - // return new InlineComponent(renderFunc); - //} - - public static VisualNode Render(Func, VisualNode> renderFunc, S? defaultValue = default) - { - return new InlineComponent(renderFunc, defaultValue); + } + + //public static VisualNode Render(Func renderFunc) + //{ + // return new InlineComponent(renderFunc); + //} + + public static VisualNode Render(Func, VisualNode> renderFunc, S? defaultValue = default) + { + return new InlineComponent(renderFunc, defaultValue); } } @@ -243,41 +243,46 @@ internal interface IComponentWithProps } public abstract class ComponentWithProps

(P? props = null) : Component, IComponentWithProps where P : class, new() - { + { private bool _derivedProps = props != null; private P? _props = props; - public P Props - { - get => _props ??= new P(); - } - - object IComponentWithProps.Props - { - get => Props; - set - { - if (_props != null) - { - throw new InvalidOperationException("Unable to set props on new component: Has Props been accessed from constructor?"); - } - - _props = (P)value; - } - } - + public P Props + { + get => _props ??= new P(); + } + + object IComponentWithProps.Props + { + get => Props; + set + { + if (_props != null) + { + throw new InvalidOperationException("Unable to set props on new component: Has Props been accessed from constructor?"); + } + + _props = (P)value; + } + } + protected override void MergeWith(VisualNode newNode) { if (!_derivedProps && newNode != this && newNode is IComponentWithProps newComponentWithProps) - { - if (newNode.GetType() == GetType()) - { - newComponentWithProps.Props = Props; - } - else - { + { + if (newNode.GetType() == GetType()) + { + newComponentWithProps.Props = Props; + } + else if (MauiReactorFeatures.HotReloadIsEnabled) + { CopyObjectExtensions.CopyProperties(Props, newComponentWithProps.Props); } + else + { + var logger = ServiceCollectionProvider.ServiceProvider?.GetService>(); + logger?.LogWarning("Unable to tranfser component Props from type {thisComponent} to {newComponent}", GetType(), newNode.GetType()); + } } base.MergeWith(newNode); @@ -288,10 +293,10 @@ protected override void MergeWith(VisualNode newNode) { private IComponentWithState? _newComponent; - private record RegisteredAction(WeakReference OwnerRef, Action Action) - { - internal bool IsOwnerAlive() => OwnerRef.TryGetTarget(out var _); - } + private record RegisteredAction(WeakReference OwnerRef, Action Action) + { + internal bool IsOwnerAlive() => OwnerRef.TryGetTarget(out var _); + } private List? _actionsRegisteredOnStateChange; @@ -303,25 +308,25 @@ protected Component(S? state = null, P? props = null) : base(props) { _state = state; - _derivedState = state != null; + _derivedState = state != null; } public S State - { + { get => _state ??= new S(); } - object IComponentWithState.State + object IComponentWithState.State { - get => State; - set - { - if (_state != null) - { - throw new InvalidOperationException("Unable to set State on new component: Has State been accessed from constructor?"); - } - _state = (S)value; - } + get => State; + set + { + if (_state != null) + { + throw new InvalidOperationException("Unable to set State on new component: Has State been accessed from constructor?"); + } + _state = (S)value; + } } IComponentWithState? IComponentWithState.NewComponent => _newComponent; @@ -345,26 +350,32 @@ protected override void OnInvalidated() void IComponentWithState.ForwardState(object stateFromOldComponent, bool invalidateComponent) { if (stateFromOldComponent.GetType() == typeof(S)) - { - _state = (S)stateFromOldComponent; + { + _state = (S)stateFromOldComponent; } - else if (stateFromOldComponent.GetType().FullName == typeof(S).FullName) - { + else if (MauiReactorFeatures.HotReloadIsEnabled && stateFromOldComponent.GetType().FullName == typeof(S).FullName) + { CopyObjectExtensions.CopyProperties(stateFromOldComponent, State); } + else + { + var logger = ServiceCollectionProvider.ServiceProvider?.GetService>(); + logger?.LogWarning("Unable to forward component State from type {State}", + stateFromOldComponent.GetType().FullName); + } + + if (_actionsRegisteredOnStateChange != null) + { + List liveActions = new(_actionsRegisteredOnStateChange.Count); + foreach (var registeredAction in _actionsRegisteredOnStateChange) + { + if (registeredAction.IsOwnerAlive()) + { + registeredAction.Action.Invoke(); + liveActions.Add(registeredAction); + } + } - if (_actionsRegisteredOnStateChange != null) - { - List liveActions = new(_actionsRegisteredOnStateChange.Count); - foreach (var registeredAction in _actionsRegisteredOnStateChange) - { - if (registeredAction.IsOwnerAlive()) - { - registeredAction.Action.Invoke(); - liveActions.Add(registeredAction); - } - } - _actionsRegisteredOnStateChange = liveActions; } @@ -397,16 +408,16 @@ private bool TryForwardStateToNewComponent(bool invalidateComponent) return false; } - protected new void Invalidate() - { - if (TryForwardInvalidateToNewComponent()) - { - return; - } - - base.Invalidate(); - } - + protected new void Invalidate() + { + if (TryForwardInvalidateToNewComponent()) + { + return; + } + + base.Invalidate(); + } + private bool TryForwardInvalidateToNewComponent() { var newComponent = _newComponent; @@ -430,43 +441,43 @@ protected void SetState(Action action, int delayMilliseconds, bool invalidate protected virtual void SetState(Action action, bool invalidateComponent = true) { - ArgumentNullException.ThrowIfNull(action); - - var currentDispather = Application.Current?.Dispatcher; - if (currentDispather != null) - { - if (currentDispather.IsDispatchRequired) - { - currentDispather.Dispatch(()=>SetState(action, invalidateComponent)); - return; - } + ArgumentNullException.ThrowIfNull(action); + + var currentDispather = Application.Current?.Dispatcher; + if (currentDispather != null) + { + if (currentDispather.IsDispatchRequired) + { + currentDispather.Dispatch(()=>SetState(action, invalidateComponent)); + return; + } } action(State); if (TryForwardStateToNewComponent(invalidateComponent)) { - return; + return; } - if (_actionsRegisteredOnStateChange != null) - { - List liveActions = new(_actionsRegisteredOnStateChange.Count); - foreach (var registeredAction in _actionsRegisteredOnStateChange) - { - if (registeredAction.IsOwnerAlive()) - { - registeredAction.Action.Invoke(); - liveActions.Add(registeredAction); - } - } - + if (_actionsRegisteredOnStateChange != null) + { + List liveActions = new(_actionsRegisteredOnStateChange.Count); + foreach (var registeredAction in _actionsRegisteredOnStateChange) + { + if (registeredAction.IsOwnerAlive()) + { + registeredAction.Action.Invoke(); + liveActions.Add(registeredAction); + } + } + _actionsRegisteredOnStateChange = liveActions; } - if (invalidateComponent && !_isMounted) - { - System.Diagnostics.Debug.WriteLine($"WARNING: You are calling SetState on an unmounted component '{this.GetType().Name}'"); + if (invalidateComponent && !_isMounted) + { + System.Diagnostics.Debug.WriteLine($"WARNING: You are calling SetState on an unmounted component '{this.GetType().Name}'"); } if (invalidateComponent && _isMounted) @@ -480,15 +491,24 @@ protected override void MergeWith(VisualNode newNode) if (!_derivedState && newNode != this && newNode is IComponentWithState newComponentWithState) { _newComponent = newComponentWithState; - if (newNode.GetType() == this.GetType()) - { - newComponentWithState.State = State; + if (newNode.GetType() == this.GetType()) + { + newComponentWithState.State = State; } - else if (newNode.GetType().FullName == this.GetType().FullName) - { - System.Diagnostics.Debug.WriteLine("WARNING: State copied!"); + else if (MauiReactorFeatures.HotReloadIsEnabled && newNode.GetType().FullName == this.GetType().FullName) + { + var logger = ServiceCollectionProvider.ServiceProvider?.GetService>(); + logger?.LogWarning("State {State} copied to new instance of component {Component}", + State.GetType().FullName, newNode.GetType().FullName); CopyObjectExtensions.CopyProperties(State, newComponentWithState.State); } + else + { + var logger = ServiceCollectionProvider.ServiceProvider?.GetService>(); + logger?.LogWarning("Unable to copy state {State} copied to new instance of component {Component}", + State.GetType().FullName, newNode.GetType().FullName); + } + } base.MergeWith(newNode); diff --git a/src/MauiReactor/MauiReactor.csproj b/src/MauiReactor/MauiReactor.csproj index 3525a543..6eaf07d8 100644 --- a/src/MauiReactor/MauiReactor.csproj +++ b/src/MauiReactor/MauiReactor.csproj @@ -10,8 +10,8 @@ enable false - 14.2 - 14.0 + 15.0 + 15.0 21.0 10.0.17763.0 10.0.17763.0 diff --git a/src/MauiReactor/Parameters/Parameter.cs b/src/MauiReactor/Parameters/Parameter.cs index b406fbd1..72321981 100644 --- a/src/MauiReactor/Parameters/Parameter.cs +++ b/src/MauiReactor/Parameters/Parameter.cs @@ -1,6 +1,7 @@ using MauiReactor.Internals; -using System.Diagnostics.CodeAnalysis; - +using Microsoft.Extensions.Logging; +using System.Diagnostics.CodeAnalysis; + namespace MauiReactor.Parameters { public interface IParameter @@ -38,8 +39,8 @@ public void Set(Action setAction, bool invalidateComponent = true) { setAction(_value); - if (invalidateComponent) - { + if (invalidateComponent) + { foreach (var componentOfReferencedParameter in _parameterReferences.ToList()) { if (componentOfReferencedParameter.TryGetTarget(out var componentOfReferencedParameterValue)) @@ -50,25 +51,25 @@ public void Set(Action setAction, bool invalidateComponent = true) { _parameterReferences.Remove(componentOfReferencedParameter); } - } + } } } public void RegisterReference(Component reference) - { - foreach (var componentOfReferencedParameter in _parameterReferences.ToList()) - { - if (componentOfReferencedParameter.TryGetTarget(out var componentOfReferencedParameterValue)) - { - if (reference == componentOfReferencedParameterValue) - { - return; - } - } - else - { - _parameterReferences.Remove(componentOfReferencedParameter); - } + { + foreach (var componentOfReferencedParameter in _parameterReferences.ToList()) + { + if (componentOfReferencedParameter.TryGetTarget(out var componentOfReferencedParameterValue)) + { + if (reference == componentOfReferencedParameterValue) + { + return; + } + } + else + { + _parameterReferences.Remove(componentOfReferencedParameter); + } } _parameterReferences.Add(new WeakReference(reference)); @@ -93,29 +94,37 @@ internal ParameterContext(Component component) _parameters.TryGetValue(name, out var parameter); if (parameter == null) - { + { var newParameterT = new Parameter(name); _parameters[name] = newParameterT; newParameterT.RegisterReference(Component); return newParameterT; } else - { - if (parameter is IParameter parameterT) - { - ((Parameter)parameterT).RegisterReference(Component); - return parameterT; + { + if (parameter is IParameter parameterT) + { + ((Parameter)parameterT).RegisterReference(Component); + return parameterT; } var newParameterT = new Parameter(name); - _parameters[newParameterT.Name] = newParameterT; - CopyObjectExtensions.CopyProperties(parameter.GetValue(), newParameterT.Value!); + if (MauiReactorFeatures.HotReloadIsEnabled) + { + CopyObjectExtensions.CopyProperties(parameter.GetValue(), newParameterT.Value!); + } + else + { + var logger = ServiceCollectionProvider.ServiceProvider?.GetService>(); + logger?.LogWarning("Unable to forward component Props from type {Props}", + parameter.GetValue().GetType().FullName); + } newParameterT.RegisterReference(Component); + return newParameterT; - return newParameterT; } } @@ -123,26 +132,35 @@ internal ParameterContext(Component component) { name ??= typeof(T).FullName ?? throw new InvalidOperationException(); - if (!_parameters.TryGetValue(name, out var parameter)) - { - return null; + if (!_parameters.TryGetValue(name, out var parameter)) + { + return null; + } + + if (parameter is IParameter parameterT) + { + ((Parameter)parameterT).RegisterReference(Component); + return parameterT; + } + + var newParameterT = new Parameter(name); + + _parameters[newParameterT.Name] = newParameterT; + + if (MauiReactorFeatures.HotReloadIsEnabled) + { + CopyObjectExtensions.CopyProperties(parameter.GetValue(), newParameterT.Value!); } + else + { + var logger = ServiceCollectionProvider.ServiceProvider?.GetService>(); + logger?.LogWarning("Unable to forward component Props from type {Props}", + parameter.GetValue().GetType().FullName); + } + + newParameterT.RegisterReference(Component); - if (parameter is IParameter parameterT) - { - ((Parameter)parameterT).RegisterReference(Component); - return parameterT; - } - - var newParameterT = new Parameter(name); - - _parameters[newParameterT.Name] = newParameterT; - - CopyObjectExtensions.CopyProperties(parameter.GetValue(), newParameterT.Value!); - - newParameterT.RegisterReference(Component); - - return newParameterT; + return newParameterT; } //internal IParameter Register(IParameterWithReferences parameterWithReferences, string? name = null) where T : new() diff --git a/src/MauiReactor/Shell.partial.cs b/src/MauiReactor/Shell.partial.cs index 94d037fe..f9939d1b 100644 --- a/src/MauiReactor/Shell.partial.cs +++ b/src/MauiReactor/Shell.partial.cs @@ -1,4 +1,5 @@ using MauiReactor.Internals; +using Microsoft.Extensions.Logging; using Microsoft.Maui.Platform; using System.Collections; @@ -422,7 +423,18 @@ public static class MauiControlsShellExtensions else { var convertedProps = new P(); - CopyObjectExtensions.CopyProperties(props, convertedProps); + + if (MauiReactorFeatures.HotReloadIsEnabled) + { + CopyObjectExtensions.CopyProperties(props, convertedProps); + } + else + { + var logger = ServiceCollectionProvider.ServiceProvider?.GetService>(); + logger?.LogWarning("Unable to forward component Props from type {Props}", + props.GetType().FullName); + } + propsInitializer(convertedProps); } }), shell)); @@ -456,7 +468,17 @@ public static class MauiControlsShellExtensions { var convertedProps = new P(); propsInitializer(convertedProps); - CopyObjectExtensions.CopyProperties(convertedProps, props); + + if (MauiReactorFeatures.HotReloadIsEnabled) + { + CopyObjectExtensions.CopyProperties(convertedProps, props); + } + else + { + var logger = ServiceCollectionProvider.ServiceProvider?.GetService>(); + logger?.LogWarning("Unable to forward component Props from type {Props}", + props.GetType().FullName); + } } }), shell));