diff --git a/src/Compatibility/Core/src/Android/AppCompat/Platform.cs b/src/Compatibility/Core/src/Android/AppCompat/Platform.cs index 471d57c195eb..fb1c31abb650 100644 --- a/src/Compatibility/Core/src/Android/AppCompat/Platform.cs +++ b/src/Compatibility/Core/src/Android/AppCompat/Platform.cs @@ -352,7 +352,7 @@ internal static IVisualElementRenderer CreateRenderer(VisualElement element, Con internal static IVisualElementRenderer CreateRenderer(VisualElement element, AndroidX.Fragment.App.FragmentManager fragmentManager, Context context) { - IVisualElementRenderer renderer = Registrar.Registered.GetHandlerForObject(element, context) ?? new DefaultRenderer(context); + IVisualElementRenderer renderer = CreateRenderer(element, context); var managesFragments = renderer as IManageFragments; managesFragments?.SetFragmentManager(fragmentManager); diff --git a/src/Compatibility/Core/src/Android/Forms.cs b/src/Compatibility/Core/src/Android/Forms.cs index ba50fb428537..072c83620056 100644 --- a/src/Compatibility/Core/src/Android/Forms.cs +++ b/src/Compatibility/Core/src/Android/Forms.cs @@ -251,6 +251,12 @@ internal static void SendViewInitialized(this VisualElement self, global::Androi static bool IsInitializedRenderers; + // Once we get essentials/cg converted to using startup.cs + // we will delete all the renderer code inside this file + internal static void RenderersRegistered() + { + IsInitializedRenderers = true; + } internal static void RegisterCompatRenderers( Assembly[] assemblies, diff --git a/src/Compatibility/Core/src/Android/HandlerToRendererShim.cs b/src/Compatibility/Core/src/Android/HandlerToRendererShim.cs index 86911cd355ee..144ae87430b6 100644 --- a/src/Compatibility/Core/src/Android/HandlerToRendererShim.cs +++ b/src/Compatibility/Core/src/Android/HandlerToRendererShim.cs @@ -42,6 +42,9 @@ public SizeRequest GetDesiredSize(int widthConstraint, int heightConstraint) public void SetElement(VisualElement element) { + if (element == Element) + return; + var oldElement = Element; if (oldElement != null) { diff --git a/src/Compatibility/Core/src/Android/Properties/AssemblyInfo.cs b/src/Compatibility/Core/src/Android/Properties/AssemblyInfo.cs index 47fb06c3ed38..70bb22191f8f 100644 --- a/src/Compatibility/Core/src/Android/Properties/AssemblyInfo.cs +++ b/src/Compatibility/Core/src/Android/Properties/AssemblyInfo.cs @@ -46,7 +46,6 @@ [assembly: ExportRenderer(typeof(CarouselPage), typeof(CarouselPageRenderer))] [assembly: ExportRenderer(typeof(Page), typeof(PageRenderer))] [assembly: ExportRenderer(typeof(FlyoutPage), typeof(FlyoutPageRenderer))] -[assembly: ExportRenderer(typeof(FlyoutPage), typeof(FlyoutPage))] [assembly: ExportRenderer(typeof(RefreshView), typeof(RefreshViewRenderer))] diff --git a/src/Compatibility/Core/src/AppHostBuilderExtensions.Controls.cs b/src/Compatibility/Core/src/AppHostBuilderExtensions.Controls.cs new file mode 100644 index 000000000000..1660f8e468d5 --- /dev/null +++ b/src/Compatibility/Core/src/AppHostBuilderExtensions.Controls.cs @@ -0,0 +1,151 @@ +#nullable enable +using System; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Maui.Controls.Compatibility; + +#if __ANDROID__ +using Microsoft.Maui.Controls.Compatibility.Platform.Android; +using Microsoft.Maui.Controls.Compatibility.Platform.Android.AppCompat; +using FrameRenderer = Microsoft.Maui.Controls.Compatibility.Platform.Android.FastRenderers.FrameRenderer; +using LabelRenderer = Microsoft.Maui.Controls.Compatibility.Platform.Android.FastRenderers.LabelRenderer; +using ImageRenderer = Microsoft.Maui.Controls.Compatibility.Platform.Android.FastRenderers.ImageRenderer; +using ButtonRenderer = Microsoft.Maui.Controls.Compatibility.Platform.Android.FastRenderers.ButtonRenderer; +#elif WINDOWS +using Microsoft.Maui.Controls.Compatibility.Platform.UWP; +using BoxRenderer = Microsoft.Maui.Controls.Compatibility.Platform.UWP.BoxViewBorderRenderer; +using CellRenderer = Microsoft.Maui.Controls.Compatibility.Platform.UWP.TextCellRenderer; +using Deserializer = Microsoft.Maui.Controls.Compatibility.Platform.UWP.WindowsSerializer; +using ResourcesProvider = Microsoft.Maui.Controls.Compatibility.Platform.UWP.WindowsResourcesProvider; +#elif __IOS__ +using Microsoft.Maui.Controls.Compatibility.Platform.iOS; +using WebViewRenderer = Microsoft.Maui.Controls.Compatibility.Platform.iOS.WkWebViewRenderer; +using NavigationPageRenderer = Microsoft.Maui.Controls.Compatibility.Platform.iOS.NavigationRenderer; +using TabbedPageRenderer = Microsoft.Maui.Controls.Compatibility.Platform.iOS.TabbedRenderer; +using FlyoutPageRenderer = Microsoft.Maui.Controls.Compatibility.Platform.iOS.PhoneFlyoutPageRenderer; +using RadioButtonRenderer = Microsoft.Maui.Controls.Compatibility.Platform.iOS.Platform.DefaultRenderer; +#endif + +using Microsoft.Maui.Hosting; +using Microsoft.Maui.Controls.Shapes; + +namespace Microsoft.Maui.Controls.Hosting +{ + public static class AppHostBuilderExtensions + { + public static IAppHostBuilder UseMauiApp(this IAppHostBuilder builder) + where TApp : class, IApplication + { + builder.ConfigureServices((context, collection) => + { + collection.AddSingleton(); + }); + + builder.SetupDefaults(); + return builder; + } + + public static IAppHostBuilder UseMauiApp(this IAppHostBuilder builder, Func implementationFactory) + where TApp : class, IApplication + { + builder.ConfigureServices((context, collection) => + { + collection.AddSingleton(implementationFactory); + }); + + builder.SetupDefaults(); + return builder; + } + + static IAppHostBuilder SetupDefaults(this IAppHostBuilder builder) + { + builder + .ConfigureMauiHandlers(handlers => + { + handlers.AddMauiControlsHandlers(); + DependencyService.SetToInitialized(); + +#if __ANDROID__ || __IOS__ || WINDOWS || MACCATALYST + + Forms.RenderersRegistered(); + handlers.TryAddCompatibilityRenderer(typeof(BoxView), typeof(BoxRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(Entry), typeof(EntryRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(Editor), typeof(EditorRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(Label), typeof(LabelRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(Image), typeof(ImageRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(Button), typeof(ButtonRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(ImageButton), typeof(ImageButtonRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(TableView), typeof(TableViewRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(ListView), typeof(ListViewRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(CollectionView), typeof(CollectionViewRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(CarouselView), typeof(CarouselViewRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(IndicatorView), typeof(IndicatorViewRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(Path), typeof(PathRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(Ellipse), typeof(EllipseRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(Line), typeof(LineRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(Polyline), typeof(PolylineRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(Polygon), typeof(PolygonRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(Rectangle), typeof(RectangleRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(RadioButton), typeof(RadioButtonRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(Slider), typeof(SliderRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(WebView), typeof(WebViewRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(SearchBar), typeof(SearchBarRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(Switch), typeof(SwitchRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(SwipeView), typeof(SwipeViewRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(DatePicker), typeof(DatePickerRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(TimePicker), typeof(TimePickerRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(Picker), typeof(PickerRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(Stepper), typeof(StepperRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(ProgressBar), typeof(ProgressBarRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(ScrollView), typeof(ScrollViewRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(ActivityIndicator), typeof(ActivityIndicatorRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(Frame), typeof(FrameRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(CheckBox), typeof(CheckBoxRenderer)); +#if !WINDOWS + handlers.TryAddCompatibilityRenderer(typeof(TabbedPage), typeof(TabbedPageRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(Shell), typeof(ShellRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(OpenGLView), typeof(OpenGLViewRenderer)); +#endif + handlers.TryAddCompatibilityRenderer(typeof(NavigationPage), typeof(NavigationPageRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(CarouselPage), typeof(CarouselPageRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(Page), typeof(PageRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(FlyoutPage), typeof(FlyoutPageRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(RefreshView), typeof(RefreshViewRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(NativeViewWrapper), typeof(NativeViewWrapperRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(Cell), typeof(CellRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(ImageCell), typeof(ImageCellRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(EntryCell), typeof(EntryCellRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(TextCell), typeof(TextCellRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(ViewCell), typeof(ViewCellRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(SwitchCell), typeof(SwitchCellRenderer)); + DependencyService.Register(); + DependencyService.Register(); + DependencyService.Register(); + DependencyService.Register(); + DependencyService.Register(); + DependencyService.Register(); +#endif + +#if __IOS__ || MACCATALYST + Internals.Registrar.RegisterEffect("Xamarin", "ShadowEffect", typeof(ShadowEffect)); +#endif + }) + .ConfigureServices(ConfigureNativeServices); + + + return builder; + } + + static void ConfigureNativeServices(HostBuilderContext arg1, IServiceCollection arg2) + { +#if WINDOWS + if (!UI.Xaml.Application.Current.Resources.ContainsKey("MauiControlsPageControlStyle")) + { + var myResourceDictionary = new Microsoft.UI.Xaml.ResourceDictionary(); + myResourceDictionary.Source = new Uri("ms-appx:///Microsoft.Maui.Controls/Platform/Windows/Styles/Resources.xbf"); + Microsoft.UI.Xaml.Application.Current.Resources.MergedDictionaries.Add(myResourceDictionary); + } +#endif + } + } +} diff --git a/src/Compatibility/Core/src/AppHostBuilderExtensions.cs b/src/Compatibility/Core/src/AppHostBuilderExtensions.cs index 923fa3b50255..536ac89c57d3 100644 --- a/src/Compatibility/Core/src/AppHostBuilderExtensions.cs +++ b/src/Compatibility/Core/src/AppHostBuilderExtensions.cs @@ -105,7 +105,7 @@ public void Configure(HostBuilderContext context, IServiceProvider services) return; } - _handlers?.AddHandler(controlType, typeof(RendererToHandlerShim)); + _handlers?.TryAddHandler(controlType, typeof(RendererToHandlerShim)); }); } #endif diff --git a/src/Compatibility/Core/src/Compatibility-net6.csproj b/src/Compatibility/Core/src/Compatibility-net6.csproj index 8172923cb969..7ba7d9acef6e 100644 --- a/src/Compatibility/Core/src/Compatibility-net6.csproj +++ b/src/Compatibility/Core/src/Compatibility-net6.csproj @@ -78,6 +78,7 @@ + @@ -93,5 +94,6 @@ + diff --git a/src/Compatibility/Core/src/Compatibility.csproj b/src/Compatibility/Core/src/Compatibility.csproj index 23a4718ea35b..01c6dd819f6d 100644 --- a/src/Compatibility/Core/src/Compatibility.csproj +++ b/src/Compatibility/Core/src/Compatibility.csproj @@ -60,6 +60,7 @@ + @@ -75,5 +76,6 @@ + diff --git a/src/Compatibility/Core/src/MauiHandlersCollectionExtensions.cs b/src/Compatibility/Core/src/MauiHandlersCollectionExtensions.cs index 749563b11b9b..474bd598f81d 100644 --- a/src/Compatibility/Core/src/MauiHandlersCollectionExtensions.cs +++ b/src/Compatibility/Core/src/MauiHandlersCollectionExtensions.cs @@ -6,11 +6,23 @@ namespace Microsoft.Maui.Controls.Compatibility { public static class MauiHandlersCollectionExtensions { + public static IMauiHandlersCollection TryAddCompatibilityRenderer(this IMauiHandlersCollection handlersCollection, Type controlType, Type rendererType) + { + // This will eventually get copied to the all the other adds once we get rid of FormsCompatBuilder + Internals.Registrar.Registered.Register(controlType, rendererType); + +#if __ANDROID__ || __IOS__ || WINDOWS || MACCATALYST + handlersCollection.TryAddHandler(controlType, typeof(RendererToHandlerShim)); +#endif + + return handlersCollection; + } + public static IMauiHandlersCollection AddCompatibilityRenderer(this IMauiHandlersCollection handlersCollection, Type controlType, Type rendererType) { FormsCompatBuilder.AddRenderer(controlType, rendererType); -#if __ANDROID__ || __IOS__ || WINDOWS +#if __ANDROID__ || __IOS__ || WINDOWS || MACCATALYST handlersCollection.AddHandler(controlType, typeof(RendererToHandlerShim)); #endif @@ -22,7 +34,7 @@ public static IMauiHandlersCollection AddCompatibilityRenderer(); #endif return handlersCollection; diff --git a/src/Compatibility/Core/src/RendererToHandlerShim.cs b/src/Compatibility/Core/src/RendererToHandlerShim.cs index bb36d6b595a1..d6b6b4c654ba 100644 --- a/src/Compatibility/Core/src/RendererToHandlerShim.cs +++ b/src/Compatibility/Core/src/RendererToHandlerShim.cs @@ -29,7 +29,7 @@ public RendererToHandlerShim() : base(ViewHandler.ViewMapper) { } -#if __ANDROID__ || __IOS__ || WINDOWS +#if __ANDROID__ || __IOS__ || WINDOWS || MACCATALYST internal IVisualElementRenderer VisualElementRenderer { get; private set; } public static IViewHandler CreateShim(object renderer) diff --git a/src/Compatibility/Core/src/WinUI/Forms.cs b/src/Compatibility/Core/src/WinUI/Forms.cs index d161400cfd9f..03f112803912 100644 --- a/src/Compatibility/Core/src/WinUI/Forms.cs +++ b/src/Compatibility/Core/src/WinUI/Forms.cs @@ -151,6 +151,12 @@ static void SetupInit( static bool IsInitializedRenderers; + // Once we get essentials/cg converted to using startup.cs + // we will delete all the renderer code inside this file + internal static void RenderersRegistered() + { + IsInitializedRenderers = true; + } internal static void RegisterCompatRenderers() { if (IsInitializedRenderers) diff --git a/src/Compatibility/Core/src/iOS/Forms.cs b/src/Compatibility/Core/src/iOS/Forms.cs index 27f4697b7a31..cf9d566f4df8 100644 --- a/src/Compatibility/Core/src/iOS/Forms.cs +++ b/src/Compatibility/Core/src/iOS/Forms.cs @@ -109,6 +109,12 @@ internal static bool IsiOS14OrNewer } } + // Once we get essentials/cg converted to using startup.cs + // we will delete all the renderer code inside this file + internal static void RenderersRegistered() + { + IsInitializedRenderers = true; + } internal static bool RespondsToSetNeedsUpdateOfHomeIndicatorAutoHidden { diff --git a/src/Controls/samples/Controls.Sample.SingleProject/Startup.cs b/src/Controls/samples/Controls.Sample.SingleProject/Startup.cs index e59e321f43e5..c797575c5bed 100644 --- a/src/Controls/samples/Controls.Sample.SingleProject/Startup.cs +++ b/src/Controls/samples/Controls.Sample.SingleProject/Startup.cs @@ -3,6 +3,7 @@ using Microsoft.Maui.Hosting; using Microsoft.AspNetCore.Components.WebView.Maui; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Maui.Controls.Hosting; namespace Maui.Controls.Sample.SingleProject { @@ -13,7 +14,6 @@ public class Startup : IStartup public void Configure(IAppHostBuilder appBuilder) { appBuilder - .UseFormsCompatibility() .RegisterBlazorMauiWebView(typeof(Startup).Assembly) .UseMauiApp(); diff --git a/src/Controls/samples/Controls.Sample/Startup.cs b/src/Controls/samples/Controls.Sample/Startup.cs index 17d8a775e949..b0a3751b5eea 100644 --- a/src/Controls/samples/Controls.Sample/Startup.cs +++ b/src/Controls/samples/Controls.Sample/Startup.cs @@ -41,9 +41,12 @@ public void Configure(IAppHostBuilder appBuilder) { bool useFullDIAndBlazor = UseFullDI || _pageType == PageType.Blazor; + if (UseXamlApp) + appBuilder.UseMauiApp(); + else + appBuilder.UseMauiApp(); + appBuilder - .UseFormsCompatibility() - .UseMauiControlsHandlers() .ConfigureMauiHandlers(handlers => { #if __ANDROID__ @@ -58,10 +61,6 @@ public void Configure(IAppHostBuilder appBuilder) #endif }); - if (UseXamlApp) - appBuilder.UseMauiApp(); - else - appBuilder.UseMauiApp(); // Use a "third party" library that brings in a massive amount of controls appBuilder.UseRed(); @@ -69,7 +68,6 @@ public void Configure(IAppHostBuilder appBuilder) #if DEBUG && !WINDOWS appBuilder.EnableHotReload(); #endif - appBuilder.UseMauiControlsHandlers(); appBuilder .ConfigureAppConfiguration(config => diff --git a/src/Controls/src/Core/AppHostBuilderExtensions.cs b/src/Controls/src/Core/AppHostBuilderExtensions.cs index 655e6aa65df1..83a969f9b9fe 100644 --- a/src/Controls/src/Core/AppHostBuilderExtensions.cs +++ b/src/Controls/src/Core/AppHostBuilderExtensions.cs @@ -3,6 +3,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Maui.Controls.Handlers; +using Microsoft.Maui.Handlers; using Microsoft.Maui.Hosting; namespace Microsoft.Maui.Controls.Hosting @@ -12,26 +13,31 @@ public static class AppHostBuilderExtensions static readonly Dictionary DefaultMauiControlHandlers = new Dictionary { { typeof(NavigationPage), typeof(NavigationPageHandler) }, +#if WINDOWS { typeof(Shell), typeof(ShellHandler) }, +#endif + { typeof(ActivityIndicator), typeof(ActivityIndicatorHandler) }, + { typeof(Button), typeof(ButtonHandler) }, + { typeof(CheckBox), typeof(CheckBoxHandler) }, + { typeof(DatePicker), typeof(DatePickerHandler) }, + { typeof(Editor), typeof(EditorHandler) }, + { typeof(Entry), typeof(EntryHandler) }, + { typeof(GraphicsView), typeof(GraphicsViewHandler) }, + { typeof(Image), typeof(ImageHandler) }, + { typeof(Label), typeof(LabelHandler) }, + { typeof(Layout), typeof(LayoutHandler) }, + { typeof(Layout2.Layout), typeof(LayoutHandler) }, + { typeof(Picker), typeof(PickerHandler) }, + { typeof(ProgressBar), typeof(ProgressBarHandler) }, + { typeof(SearchBar), typeof(SearchBarHandler) }, + { typeof(Slider), typeof(SliderHandler) }, + { typeof(Stepper), typeof(StepperHandler) }, + { typeof(Switch), typeof(SwitchHandler) }, + { typeof(TimePicker), typeof(TimePickerHandler) }, + { typeof(Page), typeof(PageHandler) } }; - public static IAppHostBuilder UseMauiControlsHandlers(this IAppHostBuilder builder) - { - return builder - .ConfigureMauiHandlers((_, handlersCollection) => handlersCollection.AddHandlers(DefaultMauiControlHandlers)) - .ConfigureServices(ConfigureNativeServices); - } - - private static void ConfigureNativeServices(HostBuilderContext arg1, IServiceCollection arg2) - { -#if WINDOWS - if (!UI.Xaml.Application.Current.Resources.ContainsKey("MauiControlsPageControlStyle")) - { - var myResourceDictionary = new Microsoft.UI.Xaml.ResourceDictionary(); - myResourceDictionary.Source = new Uri("ms-appx:///Microsoft.Maui.Controls/Platform/Windows/Styles/Resources.xbf"); - Microsoft.UI.Xaml.Application.Current.Resources.MergedDictionaries.Add(myResourceDictionary); - } -#endif - } + public static IMauiHandlersCollection AddMauiControlsHandlers(this IMauiHandlersCollection handlersCollection) + => handlersCollection.AddHandlers(DefaultMauiControlHandlers); } } diff --git a/src/Controls/src/Core/Application.cs b/src/Controls/src/Core/Application.cs index e4b362d9f1f5..7055020bc5f8 100644 --- a/src/Controls/src/Core/Application.cs +++ b/src/Controls/src/Core/Application.cs @@ -29,7 +29,10 @@ public Application() SystemResources = DependencyService.Get().GetSystemResources(); SystemResources.ValuesChanged += OnParentResourcesChanged; _platformConfigurationRegistry = new Lazy>(() => new PlatformConfigurationRegistry(this)); - // Initialize this value, when the app loads + } + + internal void PlatformServicesSet() + { _lastAppTheme = RequestedTheme; } diff --git a/src/Controls/src/Core/CompatServiceProvider.cs b/src/Controls/src/Core/CompatServiceProvider.cs index f6a0df20ea01..7c5b0f303931 100644 --- a/src/Controls/src/Core/CompatServiceProvider.cs +++ b/src/Controls/src/Core/CompatServiceProvider.cs @@ -12,6 +12,7 @@ static class CompatServiceProvider static IServiceProvider? _serviceProvider; static IEmbeddedFontLoader? _embeddedFontLoader; + // TODO MAUI This create seems wrong public static IServiceProvider ServiceProvider => _serviceProvider ??= CreateCompatServiceProvider(); public static IFontRegistrar FontRegistrar => ServiceProvider.GetRequiredService(); @@ -32,7 +33,7 @@ public static void SetFontLoader(Type loaderType) public static void SetServiceProvider(IServiceProvider services) { - if (_serviceProvider != null) + if (_serviceProvider != null && services != _serviceProvider) throw new InvalidOperationException("The service provider can only be set once."); _serviceProvider = services; diff --git a/src/Controls/src/Core/DependencyService.cs b/src/Controls/src/Core/DependencyService.cs index 2e41c3c680d0..201705b4f664 100644 --- a/src/Controls/src/Core/DependencyService.cs +++ b/src/Controls/src/Core/DependencyService.cs @@ -90,6 +90,14 @@ public static void RegisterSingleton(T instance) where T : class static Type FindImplementor(Type target) => DependencyTypes.FirstOrDefault(t => target.IsAssignableFrom(t)); + // Once we get essentials/cg converted to using startup.cs + // we will delete the initialize code from here and just use + // explicit assembly registration via startup code + internal static void SetToInitialized() + { + s_initialized = true; + } + static void Initialize() { if (s_initialized) @@ -149,4 +157,4 @@ class DependencyData public Type ImplementorType { get; set; } } } -} \ No newline at end of file +} diff --git a/src/Controls/src/Core/Device.cs b/src/Controls/src/Core/Device.cs index af953e6f529c..3b4b91eb4f8f 100644 --- a/src/Controls/src/Core/Device.cs +++ b/src/Controls/src/Core/Device.cs @@ -66,7 +66,12 @@ public static IPlatformServices PlatformServices throw new InvalidOperationException("You must call Microsoft.Maui.Controls.Forms.Init(); prior to using this property."); return s_platformServices; } - set { s_platformServices = value; } + set + { + s_platformServices = value; + if (s_platformServices != null) + Application.Current?.PlatformServicesSet(); + } } public static IPlatformInvalidate PlatformInvalidator { get; set; } @@ -165,7 +170,7 @@ public static void StartTimer(TimeSpan interval, Func callback) [EditorBrowsable(EditorBrowsableState.Never)] public static Assembly[] GetAssemblies() { - return PlatformServices.GetAssemblies(); + return AppDomain.CurrentDomain.GetAssemblies(); } [EditorBrowsable(EditorBrowsableState.Never)] diff --git a/src/Controls/src/Core/IPlatformServices.cs b/src/Controls/src/Core/IPlatformServices.cs index a4b96623852e..fb18ae9c22e1 100644 --- a/src/Controls/src/Core/IPlatformServices.cs +++ b/src/Controls/src/Core/IPlatformServices.cs @@ -18,8 +18,6 @@ public interface IPlatformServices Ticker CreateTicker(); - Assembly[] GetAssemblies(); - string GetHash(string input); [Obsolete("GetMD5Hash is obsolete as of version 4.7.0")] diff --git a/src/Controls/src/Core/Registrar.cs b/src/Controls/src/Core/Registrar.cs index b90fba5aa1b4..49bd66bdc5d3 100644 --- a/src/Controls/src/Core/Registrar.cs +++ b/src/Controls/src/Core/Registrar.cs @@ -329,10 +329,15 @@ public static void RegisterEffects(string resolutionName, ExportEffectAttribute[ for (var i = 0; i < exportEffectsLength; i++) { var effect = effectAttributes[i]; - Effects[resolutionName + "." + effect.Id] = effect.Type; + RegisterEffect(resolutionName, effect.Id, effect.Type); } } + public static void RegisterEffect(string resolutionName, string id, Type effectType) + { + Effects[resolutionName + "." + id] = effectType; + } + public static void RegisterAll(Type[] attrTypes) { RegisterAll(attrTypes, default(InitializationFlags)); @@ -384,6 +389,7 @@ public static void RegisterAll( continue; var length = attributes.Length; + for (var i = 0; i < length; i++) { var a = attributes[i]; diff --git a/src/Controls/src/Xaml/Properties/AssemblyInfo.cs b/src/Controls/src/Xaml/Properties/AssemblyInfo.cs index 89ef87125c25..943e8b48f08d 100644 --- a/src/Controls/src/Xaml/Properties/AssemblyInfo.cs +++ b/src/Controls/src/Xaml/Properties/AssemblyInfo.cs @@ -10,6 +10,7 @@ [assembly: InternalsVisibleTo("Microsoft.Maui.Controls.HotReload.Forms")] [assembly: InternalsVisibleTo("Microsoft.Maui.Controls.HotReload.UnitTests")] [assembly: InternalsVisibleTo("Microsoft.Maui.Controls.SourceGen")] +[assembly: InternalsVisibleTo("Microsoft.Maui.Controls.Compatibility")] [assembly: Preserve] [assembly: XmlnsDefinition("http://schemas.microsoft.com/dotnet/2021/maui", "Microsoft.Maui.Controls.Xaml")] diff --git a/src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj b/src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj index 26192a29ad55..bedc7996fda4 100644 --- a/src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj +++ b/src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj @@ -19,6 +19,7 @@ + diff --git a/src/Core/tests/UnitTests/Hosting/HostBuilderAppTests.cs b/src/Controls/tests/Core.UnitTests/HostBuilderAppTests.cs similarity index 56% rename from src/Core/tests/UnitTests/Hosting/HostBuilderAppTests.cs rename to src/Controls/tests/Core.UnitTests/HostBuilderAppTests.cs index ed71205217af..0a1223a7a172 100644 --- a/src/Core/tests/UnitTests/Hosting/HostBuilderAppTests.cs +++ b/src/Controls/tests/Core.UnitTests/HostBuilderAppTests.cs @@ -1,39 +1,40 @@ using Microsoft.Extensions.DependencyInjection; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Core; +using Microsoft.Maui.Handlers; using Microsoft.Maui.Hosting; -using Xunit; +using NUnit; +using NUnit.Framework; +using Microsoft.Maui.Controls.Hosting; -namespace Microsoft.Maui.UnitTests.Hosting +namespace Microsoft.Maui.Controls.Core.UnitTests { - [Category(TestCategory.Core, TestCategory.Hosting)] + [TestFixture] public class HostBuilderAppTests { - [Fact] + [Test] public void UseMauiAppRegistersApp() { var host = new AppHostBuilder() .UseMauiApp() .Build(); - var app = host.Services.GetRequiredService(); - - var stub = Assert.IsType(app); - Assert.Equal("Default", stub.Property); + var app = (ApplicationStub)host.Services.GetRequiredService(); + Assert.AreEqual("Default", app.Property); } - [Fact] + [Test] public void UseMauiAppRegistersAppWithFactory() { var host = new AppHostBuilder() .UseMauiApp(services => new ApplicationStub { Property = "Factory" }) .Build(); - var app = host.Services.GetRequiredService(); - - var stub = Assert.IsType(app); - Assert.Equal("Factory", stub.Property); + var app = (ApplicationStub)host.Services.GetRequiredService(); + Assert.AreEqual("Factory", app.Property); } - [Fact] + [Test] public void UseMauiAppRegistersSingleton() { var host = new AppHostBuilder() @@ -43,7 +44,7 @@ public void UseMauiAppRegistersSingleton() var app1 = host.Services.GetRequiredService(); var app2 = host.Services.GetRequiredService(); - Assert.Equal(app1, app2); + Assert.AreEqual(app1, app2); } } -} \ No newline at end of file +} diff --git a/src/Controls/tests/Core.UnitTests/HostBuilderHandlerTests.cs b/src/Controls/tests/Core.UnitTests/HostBuilderHandlerTests.cs new file mode 100644 index 000000000000..c97904b343e7 --- /dev/null +++ b/src/Controls/tests/Core.UnitTests/HostBuilderHandlerTests.cs @@ -0,0 +1,42 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Core; +using Microsoft.Maui.Handlers; +using Microsoft.Maui.Hosting; +using NUnit; +using NUnit.Framework; +using Microsoft.Maui.Controls.Hosting; + +namespace Microsoft.Maui.Controls.Core.UnitTests +{ + [TestFixture] + public class HostBuilderHandlerTests + { + [Test] + public void DefaultHandlersAreRegistered() + { + var host = new AppHostBuilder() + .UseMauiApp() + .Build(); + + var handler = host.Handlers.GetHandler(typeof(Button)); + + Assert.NotNull(handler); + Assert.AreEqual(handler.GetType(), typeof(ButtonHandler)); + } + + [Test] + public void CanSpecifyHandler() + { + var host = new AppHostBuilder() + .UseMauiApp() + .ConfigureMauiHandlers((_, handlers) => handlers.AddHandler()) + .Build(); + + var specificHandler = host.Handlers.GetHandler(typeof(Button)); + + Assert.NotNull(specificHandler); + Assert.AreEqual(specificHandler.GetType(), typeof(ButtonHandlerStub)); + } + } +} diff --git a/src/Controls/tests/Core.UnitTests/TestClasses/ApplicationStub.cs b/src/Controls/tests/Core.UnitTests/TestClasses/ApplicationStub.cs new file mode 100644 index 000000000000..e4b86508dd97 --- /dev/null +++ b/src/Controls/tests/Core.UnitTests/TestClasses/ApplicationStub.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; + +namespace Microsoft.Maui.Controls.Core.UnitTests +{ + class ApplicationStub : IApplication + { + List _windows = new List(); + public IReadOnlyList Windows => _windows.AsReadOnly(); + public string Property { get; set; } = "Default"; + + public IWindow CreateWindow(IActivationState activationState) + { + throw new System.NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/Core.UnitTests/TestClasses/ButtonHandlerStub.cs b/src/Controls/tests/Core.UnitTests/TestClasses/ButtonHandlerStub.cs new file mode 100644 index 000000000000..464d12c799e0 --- /dev/null +++ b/src/Controls/tests/Core.UnitTests/TestClasses/ButtonHandlerStub.cs @@ -0,0 +1,9 @@ +using Microsoft.Maui.Handlers; + +namespace Microsoft.Maui.Controls.Core.UnitTests +{ + class ButtonHandlerStub : ButtonHandler + { + + } +} \ No newline at end of file diff --git a/src/Core/src/Hosting/AppHost.cs b/src/Core/src/Hosting/AppHost.cs index 89443ea21e68..614d5b90c482 100644 --- a/src/Core/src/Hosting/AppHost.cs +++ b/src/Core/src/Hosting/AppHost.cs @@ -9,8 +9,6 @@ public static IAppHostBuilder CreateDefaultBuilder() var builder = new AppHostBuilder(); builder.UseMauiServiceProviderFactory(false); - - builder.UseMauiHandlers(); builder.ConfigureFonts(); builder.ConfigureImageSources(); diff --git a/src/Core/src/Hosting/AppHostBuilderExtensions.cs b/src/Core/src/Hosting/AppHostBuilderExtensions.cs index 7cead5864869..702b9036ec89 100644 --- a/src/Core/src/Hosting/AppHostBuilderExtensions.cs +++ b/src/Core/src/Hosting/AppHostBuilderExtensions.cs @@ -12,28 +12,6 @@ namespace Microsoft.Maui.Hosting { public static partial class AppHostBuilderExtensions { - static readonly Dictionary DefaultMauiHandlers = new Dictionary - { - { typeof(IActivityIndicator), typeof(ActivityIndicatorHandler) }, - { typeof(IButton), typeof(ButtonHandler) }, - { typeof(ICheckBox), typeof(CheckBoxHandler) }, - { typeof(IDatePicker), typeof(DatePickerHandler) }, - { typeof(IEditor), typeof(EditorHandler) }, - { typeof(IEntry), typeof(EntryHandler) }, - { typeof(IGraphicsView), typeof(GraphicsViewHandler) }, - { typeof(IImage), typeof(ImageHandler) }, - { typeof(ILabel), typeof(LabelHandler) }, - { typeof(ILayout), typeof(LayoutHandler) }, - { typeof(IPicker), typeof(PickerHandler) }, - { typeof(IProgress), typeof(ProgressBarHandler) }, - { typeof(ISearchBar), typeof(SearchBarHandler) }, - { typeof(ISlider), typeof(SliderHandler) }, - { typeof(IStepper), typeof(StepperHandler) }, - { typeof(ISwitch), typeof(SwitchHandler) }, - { typeof(ITimePicker), typeof(TimePickerHandler) }, - { typeof(IPage), typeof(PageHandler) }, - }; - public static IAppHostBuilder ConfigureMauiHandlers(this IAppHostBuilder builder, Action configureDelegate) { builder.ConfigureServices((_, handlers) => configureDelegate(handlers)); @@ -46,12 +24,6 @@ public static IAppHostBuilder ConfigureMauiHandlers(this IAppHostBuilder builder return builder; } - public static IAppHostBuilder UseMauiHandlers(this IAppHostBuilder builder) - { - builder.ConfigureMauiHandlers((_, handlersCollection) => handlersCollection.AddHandlers(DefaultMauiHandlers)); - return builder; - } - public static IAppHostBuilder ConfigureServices(this IAppHostBuilder builder, Action configureDelegate) { builder.ConfigureServices((_, services) => configureDelegate(services)); @@ -78,26 +50,6 @@ public static IAppHostBuilder ConfigureAppConfiguration(this IAppHostBuilder bui return builder; } - public static IAppHostBuilder UseMauiApp(this IAppHostBuilder builder) - where TApp : class, IApplication - { - builder.ConfigureServices((context, collection) => - { - collection.AddSingleton(); - }); - return builder; - } - - public static IAppHostBuilder UseMauiApp(this IAppHostBuilder builder, Func implementationFactory) - where TApp : class, IApplication - { - builder.ConfigureServices((context, collection) => - { - collection.AddSingleton(implementationFactory); - }); - return builder; - } - public static IAppHostBuilder UseMauiServiceProviderFactory(this IAppHostBuilder builder, bool constructorInjection) { builder.UseServiceProviderFactory(new MauiServiceProviderFactory(constructorInjection)); @@ -134,4 +86,4 @@ public void Configure(HostBuilderContext context, IServiceProvider services) } } } -} \ No newline at end of file +} diff --git a/src/Core/src/Hosting/MauiHandlersCollectionExtensions.cs b/src/Core/src/Hosting/MauiHandlersCollectionExtensions.cs index c75df282f9dc..c64758186767 100644 --- a/src/Core/src/Hosting/MauiHandlersCollectionExtensions.cs +++ b/src/Core/src/Hosting/MauiHandlersCollectionExtensions.cs @@ -41,7 +41,7 @@ public static IMauiHandlersCollection TryAddHandlers(this IMauiHandlersCollectio public static IMauiHandlersCollection TryAddHandler(this IMauiHandlersCollection handlersCollection, Type viewType, Type handlerType) { - handlersCollection.AddTransient(viewType, handlerType); + handlersCollection.TryAddTransient(viewType, handlerType); return handlersCollection; } @@ -49,7 +49,7 @@ public static IMauiHandlersCollection TryAddHandler(this IMa where TType : IFrameworkElement where TTypeRender : IViewHandler { - handlersCollection.AddTransient(typeof(TType), typeof(TTypeRender)); + handlersCollection.TryAddTransient(typeof(TType), typeof(TTypeRender)); return handlersCollection; } } diff --git a/src/Core/tests/DeviceTests/Handlers/HandlerTestBase.cs b/src/Core/tests/DeviceTests/Handlers/HandlerTestBase.cs index 7e2bb30238c2..27711cc34ed2 100644 --- a/src/Core/tests/DeviceTests/Handlers/HandlerTestBase.cs +++ b/src/Core/tests/DeviceTests/Handlers/HandlerTestBase.cs @@ -2,6 +2,7 @@ using System.Threading.Tasks; using Microsoft.Maui.DeviceTests.Stubs; using Microsoft.Maui.Graphics; +using Microsoft.Maui.Handlers; using Microsoft.Maui.Hosting; using Xunit; @@ -19,6 +20,11 @@ public HandlerTestBase() { var appBuilder = AppHost .CreateDefaultBuilder() + .ConfigureMauiHandlers(handlers => + { + handlers.AddHandler(typeof(SliderStub), typeof(SliderHandler)); + handlers.AddHandler(typeof(ButtonStub), typeof(ButtonHandler)); + }) .ConfigureImageSources((ctx, services) => { services.AddService(); diff --git a/src/Core/tests/UnitTests/Hosting/HostBuilderHandlerTests.cs b/src/Core/tests/UnitTests/Hosting/HostBuilderHandlerTests.cs index 2d7e35c4b4fe..c2489bf4f0d9 100644 --- a/src/Core/tests/UnitTests/Hosting/HostBuilderHandlerTests.cs +++ b/src/Core/tests/UnitTests/Hosting/HostBuilderHandlerTests.cs @@ -109,36 +109,6 @@ public void CanRegisterAndGetHandlerForConcreteType() Assert.IsType(handler); } - [Fact] - public void DefaultHandlersAreRegistered() - { - var host = AppHost - .CreateDefaultBuilder() - .Build(); - - var handler = host.Handlers.GetHandler(typeof(IButton)); - - Assert.NotNull(handler); - Assert.IsType(handler); - } - - [Fact] - public void CanSpecifyHandler() - { - var host = AppHost - .CreateDefaultBuilder() - .ConfigureMauiHandlers((_, handlers) => handlers.AddHandler()) - .Build(); - - var defaultHandler = host.Handlers.GetHandler(typeof(IButton)); - var specificHandler = host.Handlers.GetHandler(typeof(ButtonStub)); - - Assert.NotNull(defaultHandler); - Assert.NotNull(specificHandler); - Assert.IsType(defaultHandler); - Assert.IsType(specificHandler); - } - [Fact] public void CanChangeHandlerRegistration() {