From 5b63fbc3ee6b352fb0ad353abd87eab2d3fc8117 Mon Sep 17 00:00:00 2001 From: Chris Howarth Date: Fri, 23 Aug 2024 09:07:12 +0100 Subject: [PATCH 1/5] Add ContainerProvider --- src/Maui/Prism.Maui/Ioc/ContainerProvider.cs | 65 ++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 src/Maui/Prism.Maui/Ioc/ContainerProvider.cs diff --git a/src/Maui/Prism.Maui/Ioc/ContainerProvider.cs b/src/Maui/Prism.Maui/Ioc/ContainerProvider.cs new file mode 100644 index 000000000..31fd60bd2 --- /dev/null +++ b/src/Maui/Prism.Maui/Ioc/ContainerProvider.cs @@ -0,0 +1,65 @@ +namespace Prism.IoC; + +/// +/// Provides Types and Services registered with the Container +/// +/// The type to Resolve +/// +/// We can use this to build better types such as ValueConverters with full dependency injection +/// +/// public class MyValueConverter : IValueConverter +/// { +/// private ILoggerFacade _logger { get; } +/// public MyValueConverter(ILoggerFacade logger) +/// { +/// _logger = logger; +/// } +/// +/// public object Convert(object value, Type targetType, object parameter, CultureInfo culture) +/// { +/// _logger.Log($"Converting {value.GetType().Name} to {targetType.Name}", Category.Debug, Priority.None); +/// // do stuff +/// } +/// +/// public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) +/// { +/// _logger.Log($"Converting back from {value.GetType().Name} to {targetType.Name}", Category.Debug, Priority.None); +/// return null; +/// } +/// } +/// +/// We can then simply use our ValueConverter or other class directly in XAML +/// +/// +/// +/// +/// +/// +/// +public class ContainerProvider +{ + /// + /// The Name used to register the type with the Container + /// + public string Name { get; set; } + + /// + /// Resolves the specified type from the Application's Container + /// + /// + public static implicit operator T(ContainerProvider containerProvider) + { + var container = ContainerLocator.Container; + if (container == null) return default(T); + if (string.IsNullOrWhiteSpace(containerProvider.Name)) + { + return container.Resolve(); + } + + return container.Resolve(containerProvider.Name); + } +} From 2c4160a22b4bb8d0f026e180c73c275a6fe1b0eb Mon Sep 17 00:00:00 2001 From: Chris Howarth Date: Fri, 23 Aug 2024 13:46:20 +0100 Subject: [PATCH 2/5] Add ContainerProvider unit tests --- .../Fixtures/IoC/ContainerProviderTests.cs | 76 +++++++++++++++++++ .../Mocks/ConcreteTypeMock.cs | 6 ++ .../Mocks/Converters/MockValueConverter.cs | 27 +++++++ .../Mocks/Events/TestActionEvent.cs | 7 ++ .../Mocks/ViewModels/MockXamlViewViewModel.cs | 11 +++ .../Mocks/Views/MockXamlView.xaml | 23 ++++++ .../Mocks/Views/MockXamlView.xaml.cs | 12 +++ .../Prism.DryIoc.Maui.Tests.csproj | 6 ++ 8 files changed, 168 insertions(+) create mode 100644 tests/Maui/Prism.DryIoc.Maui.Tests/Fixtures/IoC/ContainerProviderTests.cs create mode 100644 tests/Maui/Prism.DryIoc.Maui.Tests/Mocks/ConcreteTypeMock.cs create mode 100644 tests/Maui/Prism.DryIoc.Maui.Tests/Mocks/Converters/MockValueConverter.cs create mode 100644 tests/Maui/Prism.DryIoc.Maui.Tests/Mocks/Events/TestActionEvent.cs create mode 100644 tests/Maui/Prism.DryIoc.Maui.Tests/Mocks/ViewModels/MockXamlViewViewModel.cs create mode 100644 tests/Maui/Prism.DryIoc.Maui.Tests/Mocks/Views/MockXamlView.xaml create mode 100644 tests/Maui/Prism.DryIoc.Maui.Tests/Mocks/Views/MockXamlView.xaml.cs diff --git a/tests/Maui/Prism.DryIoc.Maui.Tests/Fixtures/IoC/ContainerProviderTests.cs b/tests/Maui/Prism.DryIoc.Maui.Tests/Fixtures/IoC/ContainerProviderTests.cs new file mode 100644 index 000000000..23d2a1caf --- /dev/null +++ b/tests/Maui/Prism.DryIoc.Maui.Tests/Fixtures/IoC/ContainerProviderTests.cs @@ -0,0 +1,76 @@ +using Prism.DryIoc.Maui.Tests.Mocks; +using Prism.DryIoc.Maui.Tests.Mocks.Events; +using Prism.DryIoc.Maui.Tests.Mocks.ViewModels; +using Prism.DryIoc.Maui.Tests.Mocks.Views; +using Prism.Events; +using Prism.IoC; + +namespace Prism.DryIoc.Maui.Tests.Fixtures.IoC; + +public class ContainerProviderTests(ITestOutputHelper testOutputHelper) : TestBase(testOutputHelper) +{ + [Fact] + public void CanResolveUnamedType() + { + var builder = CreateBuilder(prism => { }); + var app = builder.Build(); + + var containerProvider = new ContainerProvider(); + ConcreteTypeMock type = (ConcreteTypeMock)containerProvider; + + Assert.NotNull(type); + Assert.IsType(type); + } + + [Fact] + public void CanResolvedNamedType() + { + var builder = CreateBuilder(prism => { }); + var app = builder.Build(); + var containerProvider = new ContainerProvider + { + Name = ConcreteTypeMock.Key + }; + + ConcreteTypeMock vm = (ConcreteTypeMock)containerProvider; + + Assert.NotNull(vm); + Assert.IsType(vm); + } + + [Fact] + public async Task ProvidesValueFromResourceDictionary() + { + var builder = CreateBuilder(prism => + { + prism.RegisterTypes(containerRegistry => + { + containerRegistry.RegisterForNavigation(); + }) + .CreateWindow(n => + n.CreateBuilder() + .AddSegment() + .NavigateAsync()); + }); + var app = builder.Build(); + + var ea = app.Services.GetService(); + var events = new List(); + ea.GetEvent().Subscribe((m) => events.Add(m)); + + var navigation = app.Services.GetService(); + await navigation.CreateBuilder() + .AddSegment() + .NavigateAsync(); + + Assert.Contains(events, e => e == "Convert"); + var window = GetWindow(app); + Assert.NotNull(window.Page); + + var xamlView = window.Page as MockXamlView; + var viewModel = xamlView.BindingContext as MockXamlViewViewModel; + + xamlView.TestEntry.Text = "Foo Bar"; + Assert.Contains(events, e => e == "ConvertBack"); + } +} diff --git a/tests/Maui/Prism.DryIoc.Maui.Tests/Mocks/ConcreteTypeMock.cs b/tests/Maui/Prism.DryIoc.Maui.Tests/Mocks/ConcreteTypeMock.cs new file mode 100644 index 000000000..82957cb47 --- /dev/null +++ b/tests/Maui/Prism.DryIoc.Maui.Tests/Mocks/ConcreteTypeMock.cs @@ -0,0 +1,6 @@ +namespace Prism.DryIoc.Maui.Tests.Mocks; + +internal class ConcreteTypeMock +{ + public const string Key = "ConcreteTypeMock"; +} diff --git a/tests/Maui/Prism.DryIoc.Maui.Tests/Mocks/Converters/MockValueConverter.cs b/tests/Maui/Prism.DryIoc.Maui.Tests/Mocks/Converters/MockValueConverter.cs new file mode 100644 index 000000000..c1d0a4609 --- /dev/null +++ b/tests/Maui/Prism.DryIoc.Maui.Tests/Mocks/Converters/MockValueConverter.cs @@ -0,0 +1,27 @@ +using System.Globalization; +using Prism.DryIoc.Maui.Tests.Mocks.Events; +using Prism.Events; + +namespace Prism.DryIoc.Maui.Tests.Mocks.Converters; + +internal class MockValueConverter : IValueConverter +{ + private IEventAggregator _eventAggreator { get; } + + public MockValueConverter(IEventAggregator eventAggreator) + { + _eventAggreator = eventAggreator; + } + + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + _eventAggreator.GetEvent().Publish("Convert"); + return value; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + _eventAggreator.GetEvent().Publish("ConvertBack"); + return value; + } +} diff --git a/tests/Maui/Prism.DryIoc.Maui.Tests/Mocks/Events/TestActionEvent.cs b/tests/Maui/Prism.DryIoc.Maui.Tests/Mocks/Events/TestActionEvent.cs new file mode 100644 index 000000000..b0450f26d --- /dev/null +++ b/tests/Maui/Prism.DryIoc.Maui.Tests/Mocks/Events/TestActionEvent.cs @@ -0,0 +1,7 @@ +using Prism.Events; + +namespace Prism.DryIoc.Maui.Tests.Mocks.Events; + +internal class TestActionEvent : PubSubEvent +{ +} diff --git a/tests/Maui/Prism.DryIoc.Maui.Tests/Mocks/ViewModels/MockXamlViewViewModel.cs b/tests/Maui/Prism.DryIoc.Maui.Tests/Mocks/ViewModels/MockXamlViewViewModel.cs new file mode 100644 index 000000000..da95836cd --- /dev/null +++ b/tests/Maui/Prism.DryIoc.Maui.Tests/Mocks/ViewModels/MockXamlViewViewModel.cs @@ -0,0 +1,11 @@ +namespace Prism.DryIoc.Maui.Tests.Mocks.ViewModels; + +internal class MockXamlViewViewModel : BindableBase +{ + private string _test = "Initial Value"; + public string Test + { + get => _test; + set => SetProperty(ref _test, value); + } +} diff --git a/tests/Maui/Prism.DryIoc.Maui.Tests/Mocks/Views/MockXamlView.xaml b/tests/Maui/Prism.DryIoc.Maui.Tests/Mocks/Views/MockXamlView.xaml new file mode 100644 index 000000000..63552a756 --- /dev/null +++ b/tests/Maui/Prism.DryIoc.Maui.Tests/Mocks/Views/MockXamlView.xaml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + diff --git a/tests/Maui/Prism.DryIoc.Maui.Tests/Mocks/Views/MockXamlView.xaml.cs b/tests/Maui/Prism.DryIoc.Maui.Tests/Mocks/Views/MockXamlView.xaml.cs new file mode 100644 index 000000000..c5aa846e8 --- /dev/null +++ b/tests/Maui/Prism.DryIoc.Maui.Tests/Mocks/Views/MockXamlView.xaml.cs @@ -0,0 +1,12 @@ +namespace Prism.DryIoc.Maui.Tests.Mocks.Views; + +[XamlCompilation(XamlCompilationOptions.Compile)] +public partial class MockXamlView : ContentPage +{ + public MockXamlView() + { + InitializeComponent(); + } + + public Entry TestEntry => testEntry; +} diff --git a/tests/Maui/Prism.DryIoc.Maui.Tests/Prism.DryIoc.Maui.Tests.csproj b/tests/Maui/Prism.DryIoc.Maui.Tests/Prism.DryIoc.Maui.Tests.csproj index 8e3eaacd0..57797a54d 100644 --- a/tests/Maui/Prism.DryIoc.Maui.Tests/Prism.DryIoc.Maui.Tests.csproj +++ b/tests/Maui/Prism.DryIoc.Maui.Tests/Prism.DryIoc.Maui.Tests.csproj @@ -32,4 +32,10 @@ + + + MSBuild:Compile + + + From f9ccc6834fc9be0e323ea5c51b111b9a6ad73460 Mon Sep 17 00:00:00 2001 From: Chris Howarth Date: Fri, 23 Aug 2024 19:02:46 +0100 Subject: [PATCH 3/5] Remove unused test variables --- .../Fixtures/IoC/ContainerProviderTests.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/Maui/Prism.DryIoc.Maui.Tests/Fixtures/IoC/ContainerProviderTests.cs b/tests/Maui/Prism.DryIoc.Maui.Tests/Fixtures/IoC/ContainerProviderTests.cs index 23d2a1caf..ceb1bf041 100644 --- a/tests/Maui/Prism.DryIoc.Maui.Tests/Fixtures/IoC/ContainerProviderTests.cs +++ b/tests/Maui/Prism.DryIoc.Maui.Tests/Fixtures/IoC/ContainerProviderTests.cs @@ -12,10 +12,8 @@ public class ContainerProviderTests(ITestOutputHelper testOutputHelper) : TestBa [Fact] public void CanResolveUnamedType() { - var builder = CreateBuilder(prism => { }); - var app = builder.Build(); - var containerProvider = new ContainerProvider(); + ConcreteTypeMock type = (ConcreteTypeMock)containerProvider; Assert.NotNull(type); @@ -25,8 +23,6 @@ public void CanResolveUnamedType() [Fact] public void CanResolvedNamedType() { - var builder = CreateBuilder(prism => { }); - var app = builder.Build(); var containerProvider = new ContainerProvider { Name = ConcreteTypeMock.Key From 6a44b0636972470dc6fa656fb4e34059e7d1f7e1 Mon Sep 17 00:00:00 2001 From: Chris Howarth Date: Tue, 27 Aug 2024 08:34:38 +0100 Subject: [PATCH 4/5] Address PR comments --- src/Maui/Prism.Maui/Ioc/ContainerProvider.cs | 8 +++++--- .../Prism.DryIoc.Maui.Tests.csproj | 6 ------ 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/Maui/Prism.Maui/Ioc/ContainerProvider.cs b/src/Maui/Prism.Maui/Ioc/ContainerProvider.cs index 31fd60bd2..c2c25858f 100644 --- a/src/Maui/Prism.Maui/Ioc/ContainerProvider.cs +++ b/src/Maui/Prism.Maui/Ioc/ContainerProvider.cs @@ -1,3 +1,4 @@ +#nullable enable namespace Prism.IoC; /// @@ -9,8 +10,9 @@ namespace Prism.IoC; /// /// public class MyValueConverter : IValueConverter /// { -/// private ILoggerFacade _logger { get; } -/// public MyValueConverter(ILoggerFacade logger) +/// private readonly ILogger _logger { get; } +/// +/// public MyValueConverter(ILogger logger) /// { /// _logger = logger; /// } @@ -45,7 +47,7 @@ public class ContainerProvider /// /// The Name used to register the type with the Container /// - public string Name { get; set; } + public string? Name { get; set; } /// /// Resolves the specified type from the Application's Container diff --git a/tests/Maui/Prism.DryIoc.Maui.Tests/Prism.DryIoc.Maui.Tests.csproj b/tests/Maui/Prism.DryIoc.Maui.Tests/Prism.DryIoc.Maui.Tests.csproj index 57797a54d..8e3eaacd0 100644 --- a/tests/Maui/Prism.DryIoc.Maui.Tests/Prism.DryIoc.Maui.Tests.csproj +++ b/tests/Maui/Prism.DryIoc.Maui.Tests/Prism.DryIoc.Maui.Tests.csproj @@ -32,10 +32,4 @@ - - - MSBuild:Compile - - - From a43fcc7c57a82dab67b4c82628373fe39722eff8 Mon Sep 17 00:00:00 2001 From: Chris Howarth Date: Tue, 27 Aug 2024 18:26:55 +0100 Subject: [PATCH 5/5] Add back app builder use in tests --- .../Fixtures/IoC/ContainerProviderTests.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/Maui/Prism.DryIoc.Maui.Tests/Fixtures/IoC/ContainerProviderTests.cs b/tests/Maui/Prism.DryIoc.Maui.Tests/Fixtures/IoC/ContainerProviderTests.cs index ceb1bf041..2188cf3f9 100644 --- a/tests/Maui/Prism.DryIoc.Maui.Tests/Fixtures/IoC/ContainerProviderTests.cs +++ b/tests/Maui/Prism.DryIoc.Maui.Tests/Fixtures/IoC/ContainerProviderTests.cs @@ -12,6 +12,8 @@ public class ContainerProviderTests(ITestOutputHelper testOutputHelper) : TestBa [Fact] public void CanResolveUnamedType() { + var builder = CreateBuilder(prism => { }); + var app = builder.Build(); var containerProvider = new ContainerProvider(); ConcreteTypeMock type = (ConcreteTypeMock)containerProvider; @@ -23,6 +25,8 @@ public void CanResolveUnamedType() [Fact] public void CanResolvedNamedType() { + var builder = CreateBuilder(prism => { }); + var app = builder.Build(); var containerProvider = new ContainerProvider { Name = ConcreteTypeMock.Key