uno-platform

Host is null when trying to access from MainPage


I have created a new Uno Platform app and am trying to inject environment specific appSettings.json data into the pages.

So far I import the settings;

.UseConfiguration(configure: configBuilder =>
     configBuilder
         .EmbeddedSource<App>()
         .Section<AppConfig>()
         .Section<ProjectorSettings>()
         .Section<HoleSettings>()
)

and I register my routes as follows;

 private static void RegisterRoutes(IViewRegistry views, IRouteRegistry routes)
 {
     views.Register(
         new ViewMap(ViewModel: typeof(ShellModel)),
         new ViewMap<MainPage, MainModel>(),
         new ViewMap<BallPathPage, BallPathModel>()
     );

     routes.Register(
         new RouteMap("", View: views.FindByViewModel<ShellModel>(),
             Nested:
             [
                 new("Main", View: views.FindByViewModel<MainModel>(), IsDefault: true),
                 new("BallPath", View: views.FindByViewModel<BallPathModel>())
             ]
         )
     );
 }

Then in my MainModel.cs I inject the IOptions in;

public MainModel(
        IStringLocalizer localizer,
        IOptions<AppConfig> appInfo,
        IOptions<ProjectorSettings> projectorSettingsOptions,
        IOptions<HoleSettings> holeSettingsOptions,
        INavigator navigator)
    {

        projectorSettings = projectorSettingsOptions.Value;
        holeSettings = holeSettingsOptions.Value;

        _navigator = navigator;
    }

Finally, I try to access from my MainPage.xaml.cs, where try to get the MainModel;

    {      
        InitializeComponent();

        var app = Application.Current as App;
        app?.MainWindow?.AppWindow.SetPresenter(Microsoft.UI.Windowing.AppWindowPresenterKind.FullScreen);

        var mainModel = (Application.Current as App)?.Host?.Services.GetRequiredService<MainModel>();

        _projectorSettings = mainModel.projectorSettings;
        _holeSettings = mainModel.holeSettings;

    }

However when I try this Host is null when hitting the MainPage constructor? Can anyonw tell me what I am doing wrong here please?


Solution

  • By the time MainPage is instantiated, Host is not set yet. Place breakpoints at the Host's setter and the MainPage's constructor, and you'll see that the MainPage's constructor is hit first.

    Add a Button on MainPage and you'll see that you can get Host without problem.

    If you want to get the Host as soon as it gets available, you could do:

    App.xaml.cs

    public event EventHandler<IHost>? HostReady;
    
    private IHost? _host;
    
    public IHost? Host
    {
        get => _host;
        private set
        {
            _host = value;
    
            if (_host is not null)
            {
                HostReady?.Invoke(this, _host);
            }
        }
    }
    

    MainPage.xaml.cs

    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
            Loaded += MainPage_Loaded;
            Unloaded += MainPage_Unloaded;
        }
        private void MainPage_Loaded(object sender, RoutedEventArgs e)
        {
            if (Application.Current is not App app)
            {
                return;
            }
    
            app.HostReady += App_HostReady;
        }
    
        private void MainPage_Unloaded(object sender, RoutedEventArgs e)
        {
            if (Application.Current is not App app)
            {
                return;
            }
    
            app.HostReady -= App_HostReady;
        }
    
        private void App_HostReady(object? sender, IHost host)
        {
            var mainModel = host.Services?.GetRequiredService<MainModel>();
        }
    }