1

My problem is that I'm referencing a static resource, primary (as a color) in my MainPage, but when I have MainPage in the constructor of App() for Dependency Injection, primary isn't defined yet because its reference is loaded from App.xaml.

public partial class App : Application
{
    //MainPage gets loaded first with a reference to
    //StaticResource Primary which doesn't exist yet.
    //An exception is thrown in mp.InitializeComponent()
    //complaining about StaticResource Primary not existing
    public App(MainPage mp, MainPageViewModel vm)
    {
        //StaticResource Primary is defined in here
        InitializeComponent();

        MainPage = mp;
        MainPage.BindingContext= vm;
    }
}

I can work around this by doing the following:

Adding Colors (and Styles) to the ResourceDictionary of MainPage:

<ContentPage.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="Resources/Styles/Colors.xaml" />
            <ResourceDictionary Source="Resources/Styles/Styles.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</ContentPage.Resources>

But then I also have to add a ResourceDictionary in Styles.xaml referencing Colors.xaml:

<ResourceDictionary>
    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="Colors.xaml" />
    </ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

This approach is fine for a small app, but I have many view pages utilizing Colors.xaml in the app I'm developing. Is there any way I can globally reference Colors.xaml and Styles.xaml in MauiProgram.cs? (So they're registered before DI takes place with MainPage)

XJonOneX
  • 305
  • 2
  • 11
  • *Why* do you pass `MainPage` in as a constructor parameter? Do you have some scenario that requires that? Alternative is to remove that parameter; instead do `MainPage = new MainPage();`. – ToolmakerSteve Nov 10 '22 at 02:40
  • I pass MainPage as a constructor parameter because, well, dependency injection. It's how articles and videos I've seen do it. You're not supposed to new() up anything, right? In the app I'm developing, the MainPage needs to pass down dependencies to different navigation pages, and I'm trying to keep in line with the DI paradigm of letting the DI Container do the instantiating. If I do `MainPage = new MainPage()` I'd have to pass in parameters, which in turn I'd have to instantiate, then that just dominos down the line. – XJonOneX Nov 10 '22 at 03:16
  • 1
    Interesting. First time I've seen MainPage itself passed in as a constructor parameter. `MainPageViewModel` isn't sufficient? Your design may have a fundamental problem with order of initialization. App can't construct until there is a MainPage; MainPage can't construct until App has created app resources. That's a problem. DI might not work here. `MainPage = new MainPage(vm);` would be better. – ToolmakerSteve Nov 10 '22 at 05:09
  • Yea, I'm gonna restructure some things, thanks for helping. – XJonOneX Nov 10 '22 at 18:10

1 Answers1

1

You don't need to reference colors. What you actually ask is: "How to resolve services with dependency injection".

You can add to any class IServiceProvider, and "ask" for a service to be provided to you. When you "ask" for your View, it will cascade (or to use your term: dominos down the line) and call the required constructors for ViewModel. And if your ViewModel uses something like ISettings, It will call the constructor of your MySettings class that implements the interface and so on.

The whole idea of using DI is to let it do this work for you.

You should not pass pages, in the constructor of you Application class. Why? Because when you construct it, LoadFromXaml is not called yet. But nothing is stopping you from having IServiceProvider in your constructor. And request services after Initialization is done.

This is good theory: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-7.0

This is good example: https://stackoverflow.com/a/32461714/6643940

H.A.H.
  • 2,104
  • 1
  • 8
  • 21
  • Thanks for your help, I'm going to restructure some things. – XJonOneX Nov 10 '22 at 18:15
  • @H.A.H., it would be great to add to this answer the specific lines of code needed to 1) "add to any class IServiceProvider" and 2) "ask for the MainPage class". This would show the changes to make to these lines of code in question: `public App(MainPage mp, MainPageViewModel vm)`, and `MainPage = mp;`. – ToolmakerSteve Nov 10 '22 at 21:25
  • 1
    @XJonOneX I have added some links, you should go over the theory, and pay more attention to the example. – H.A.H. Nov 11 '22 at 11:13