unoplatform / uno.extensions

Libraries to ease common developer tasks associated with building multi-platform mobile, desktop and web applications using Uno Platform or WinAppSDK.
https://platform.uno/
Other
73 stars 47 forks source link

Injected INavigator is null for classes not linked to View #2608

Open KWodarczyk opened 2 weeks ago

KWodarczyk commented 2 weeks ago

Current behavior

I have SomeUtils class that takes UnoAppNavigation2.zip in INavigator as ctor parameter, at creation the parameter is null

image

App.xaml.cs

...omitted for brevity 
                .ConfigureServices((context, services) =>
                {
                    // TODO: Register your services
                    //services.AddSingleton<IMyService, MyService>();

                    services.AddSingleton<ISomeUtils, SomeUtils>();
                })
                .UseNavigation(RegisterRoutes)
            );
        MainWindow = builder.Window;

#if DEBUG
        MainWindow.EnableHotReload();
#endif
        MainWindow.SetWindowIcon();

        Host = builder.Build();

        await builder.NavigateAsync<Shell>();
    }

    private void RegisterRoutes(IViewRegistry views, IRouteRegistry routes)
    {
        views.Register(
            new ViewMap(ViewModel: typeof(ShellViewModel)),
            new ViewMap<MainPage, MainViewModel>(),
            new ViewMap<FirstPage, FirstViewModel>(),
            new DataViewMap<SecondPage, SecondViewModel, Entity>()
        );

        routes.Register(
            new RouteMap("", View: views.FindByViewModel<ShellViewModel>(),
                Nested:
                [
                    new ("Main", View: views.FindByViewModel<MainViewModel>(),IsDefault:true)
                ]
            )
        );
    }
}

MainPage.xaml cs getting ISomeUtils class instance

    public MainPage()
    {
        _app = (Application.Current as App);

        var somUtils = _app.Host.Services.GetRequiredService<ISomeUtils>();

        INavigator navigator = this.Navigator();

        this.InitializeComponent();

        UrlPath.Text =  _app?.MainHref + " base url:"+_app.BaseUrl;
    }

SomeUtils class

public class SomeUtils : ISomeUtils
{
    private INavigator _navigation;

    public SomeUtils(INavigator navigator)
    {
        _navigation = navigator;
    }

    public int MyProperty { get; set; }
}

Expected behavior

INavigator should not be null when injected to a SomeUtils class

How to reproduce it (as minimally and precisely as possible)

Build and run project attached, put a brakepoint in SomeUtlis class ctor. INavigator parameter will be null.

Workaround

No response

Works on UWP/WinUI

None

Environment

Uno.UI / Uno.UI.WebAssembly / Uno.UI.Skia

NuGet package version(s)

No response

Affected platforms

Windows (WinAppSDK)

IDE

Visual Studio 2022

IDE version

No response

Relevant plugins

No response

Anything else we need to know?

No response

lhLife commented 6 days ago

modify to: services.AddTransient<ISomeUtils, SomeUtils>(); 

KWodarczyk commented 6 days ago

@lhLife .AddTransient does fix the issue but, it's not ideal as it forces developer to use Transient, even if they want a Singleton, I would treat this as temporary work around. I also think that this should be documented in Uno docs for example somewhere on this page https://platform.uno/docs/articles/external/uno.extensions/doc/Reference/Navigation/Navigator.html

lhLife commented 5 days ago

It cannot be a singleton, it can only expose INavigatorFactory or INavigator wrapper。 The entire program is a tree like structure that can be navigated anywhere。 demo:Not real code Where do you think INavigator should navigate from

<Page>
    <Frame Navigator="FrameNavigator">
        <Page2>
            <Panel1 Navigator="PanelVisiblityNavigator">
                <Page3/>
            </Panel1>
            <Panel2 Navigator="PanelVisiblityNavigator">
                <Page4/>
            </Panel2>
        </Page2>
    </Frame>
</Page>
lhLife commented 5 days ago

The setting of the region is good, but INavigator needs a wrapper class to solve its complexity.

KWodarczyk commented 5 days ago

It cannot be a singleton, it can only expose INavigatorFactory or INavigator wrapper。 The entire program is a tree like structure that can be navigated anywhere。 demo:Not real code Where do you think INavigator should navigate from

<Page>
    <Frame Navigator="FrameNavigator">
        <Page2>
            <Panel1 Navigator="PanelVisiblityNavigator">
                <Page3/>
            </Panel1>
            <Panel2 Navigator="PanelVisiblityNavigator">
                <Page4/>
            </Panel2>
        </Page2>
    </Frame>
</Page>

Sorry I don't follow, you have two regions with same name ?

lhLife commented 3 days ago

Each page is a separate page. When you navigate through the Model on Page 4, there are PanelVisilityNavigator and FrameNavigator at the top level, and multiple options will appear. Therefore, they can only be Transient (PanelVisilityNavigator)