SirJohnK/LocalizationResourceManager.Maui

How to Use in a ContentView

Closed this issue · 1 comments

How would I use/provide this ILocalizationResourceManager instance to a Code-Behind of a ContentView?
I registered the Code-Behind in MauiProgram.cs via builder.Services.AddTransient<MyContentView>();, but when I try to use it as follows, it just says that it can't be used like this and needs a default constructor. So, how would I use this in a ContentView?

public partial class MyContentView : ContentView
{
    private readonly ILocalizationResourceManager resourceManager;

    public MyContentView(ILocalizationResourceManager resourceManager)
    {
    
    }
}

@DeveloperOnGitHub, unfortunately a ContentView will not be automatically resolved from the DI container. So that means you have to resolve the ContentView or ILocalizationResourceManager by yourself. To accomplish this, you need a reference to the DI ServiceProvider.

This could be solved in many ways, but I am fond of using a static class to store and access the ServiceProvider:

/// <summary>
/// Store and access a service provider to resolve specific types.
/// </summary>
internal static class ServiceResolver
{
    private static IServiceProvider? _serviceProvider;
    public static IServiceProvider ServiceProvider => _serviceProvider ?? throw new Exception("Service provider has not been initialized");

    /// <summary>
    /// Register the service provider
    /// </summary>
    public static void RegisterServiceProvider(IServiceProvider sp)
    {
        _serviceProvider = sp;
    }

    /// <summary>
    /// Get service of type <typeparamref name="T"/> from the service provider.
    /// </summary>
    public static T Resolve<T>() where T : class
        => ServiceProvider.GetRequiredService<T>();

    public static void UseResolver(this IServiceProvider sp)
    {
        RegisterServiceProvider(sp);
    }
}

Register the ServiceProvider with the UseResolver extension method or the RegisterServiceProvider method. Get the ServiceProvider reference in the CreateMauiApp method in MauiProgram.cs or my prefered way, inject the IServiceProvider interface in a custom Application class:

/// <summary>
/// Custom Application for Service Provider registering.
/// </summary>
/// <remarks>Use as new App base class for Maui Application!</remarks>
public abstract class ServiceProviderApplication : Application
{
    /// <summary>
    /// Constructor for injecting current Service Provider.
    /// </summary>
    /// <param name="serviceProvider">Current Service Provider.</param>
    public ServiceProviderApplication(IServiceProvider serviceProvider)
    {
        //Store Current Service Provider
        serviceProvider.UseResolver();
    }
}

Update your App.xaml AND App.xaml.cs to use the the custom Application class:

public partial class App : ServiceProviderApplication
{
    public App(IServiceProvider serviceProvider) : base(serviceProvider)
    {
        InitializeComponent();

Now you can access the ServiceProvider anywhere in your application and resolve anything registered in DI! 😃

In your case, you could resolve the ILocalizationResourceManager:

public partial class MyContentView : ContentView
{
    private readonly ILocalizationResourceManager resourceManager;

    public MyContentView()
    {
        resourceManager = ServiceResolver.Resolve<ILocalizationResourceManager>();
    }
}

Come to think of it, I should probably write a blog about this! 😜

Hope this helps!