MPowerKit / Navigation

.NET MAUI MVVM navigation framework. It supports regular/modal navigation, opening/closing windows, regions
MIT License
21 stars 2 forks source link

Issue in Navigating Back #2

Open dharamhbtik opened 2 weeks ago

dharamhbtik commented 2 weeks ago

I am replacing the PRISM from my MAUI project targeting .NET 8. Here is sample code Ö

.UseMPowerKitNavigation(b=>
                {
                    b.ConfigureServices(s =>
                    {
                        s.RegisterForNavigation<StyledNavigationPage>();
                        MauiProgramExtension.RegisterPages(s);
                    })
                    .OnAppStart($"{nameof(LoginPage)}");

And after login, I am navigating something like this

 var parameters = new NavigationParameters
                        {
                             { BasePageVIewModel.InitPageKey, true },
                             { BasePageVIewModel.InitiSetupModeKey, true }
                        };

                        var result = await _navigationService.NavigateAsync($"/{nameof(NavigationPage)}/{nameof(HomePage)}", parameters);

Now from this home page, I am opening new pages which I need to close using GoBackAsync method var result= await NavigationService.NavigateAsync<ResultVIewModel>($"/{nameof(NavigationPage)}/{nameof(ResultViewPage)}", parms, true,true);

and this NavigateAsync is extension method which is written s below


public static async Task<TViewModel> NavigateAsync<TViewModel>(
            this INavigationService self,
            string name,
            NavigationParameters parameters = null,
            bool useModalNavigation = false,
            bool animated = true
        )
            where TViewModel : PageViewModel
        {
            var wrapper = new TaskCompletionSource<object>();

            parameters = parameters ?? new NavigationParameters();
            parameters.Add(KnownNavigationParameters.IsNavigatedModally, useModalNavigation);
           parameters.Add(BaseViewModel.To, wrapper);
           var result =  await self.NavigateAsync($"{name}", parameters, useModalNavigation, true);
            if (result.Success)
            {
                return await wrapper.Task as TViewModel;
            }
            else
            {
                throw result.Exception;
            }
        }

Now this navigation is also setting the main Page as the current page and when I am going back from the view model using below code

await _navigationService.GoBackAsync(); this line is throwing exception that cannot navigate back from mainpage of the window

Anything wrong I am doing here?

Alex-Dobrynin commented 2 weeks ago

Im not sure I can understand what you are trying to do. If you want to open somepage from homepage and then go back from that somepage, you dont need to open somepage as absolute navigation, because it will overwrite navigation stack. so from loginpage you need to do await _navigationService.NavigateAsync($"/{nameof(NavigationPage)}/{nameof(HomePage)}", parameters);, then you might want to open somepage from homepage as next await _navigationService.NavigateAsync($"{nameof(SomePage)}", parameters);, and then you can go back from somepage to home page by using GoBackAsync

Remember, that / before the path is meaning you are doing absolute navigation which will overwrite navigation stack. that is why you are getting that error, because you have overwritten homepage by your ResultViewPage

Alex-Dobrynin commented 2 weeks ago

Also, it is not a good idea to pass a viewmodel as a result of navigation. it breaks MVVM pattern. if you need to communicate between viewmodels better to use EventAggregator from MPowerKit.Events package

dharamhbtik commented 2 weeks ago

Noted. But when I am not using the / then it throwing error something like cannot navigate through root or something. I will try and will provide you the exact error.

Alex-Dobrynin commented 2 weeks ago

better to give me test project, where i can see it by my self

dharamhbtik commented 2 weeks ago

Sure. I will create a test project and will upload here. But my workflow is like:

OnAppStart("LoginPage")

after login page _navigationService.NavigateAsync("/NavigationPage/HomePage");

from home page opening new page from where I need to come back, and I am opening it from ViewModel like this

_navigationService.NavigateAsync("NavigationPage/ResultPage");

and from ResultPageViewModel, I am doing like this :

await _navigationService.GoBackAsync();

then it is giving error as below : "Cannot navigate back from inactvie page"

Alex-Dobrynin commented 2 weeks ago

thats a big mistake doing this _navigationService.NavigateAsync("NavigationPage/ResultPage");, since you are already have navigationpage in your stack, just _navigationService.NavigateAsync("ResultPage");

dharamhbtik commented 2 weeks ago

_navigationService.NavigateAsync("ResultPage"); using this also giving error as Cannot navigate back from inactvie page. in the NavigationService var currentPage = GetCurrentPage()!; if (!IsActiveViewAttached.GetIsActiveView(currentPage)) { throw new InvalidOperationException("Cannot navigate back from inactvie page"); }

this code, the currentPage is coming as HomePage instead of ResultPage.

Anyway, I will create and upload a sample here for your reference.

kerberosargos commented 2 days ago

Same issue has for me too.

kerberosargos commented 2 days ago

Hello again, firstly thank you for your great job

When I use as following codes;

  private readonly INavigationService NavigationService;

  public BaseViewModel()
  {
      NavigationService = Application.Current?.Handler?.MauiContext?.Services?.GetService<INavigationService>();
  }

 public ICommand GoBackCommand => new Command(async () =>
 {

     try
     {

         IsBusy = true;

         var nsresult = await NavigationService.GoBackAsync();

         if (!nsresult.Success)
         {
             throw nsresult.Exception;
         }

     }
     catch (Exception exception)
     {
         Console.WriteLine(exception);
     }
     finally
     {

         IsBusy = false;
     }

I am getting as following error;

"Window does not exist"

Thank you in advance

Alex-Dobrynin commented 2 days ago

@kerberosargos INavigationService is not registered as singleton nor transient, it is registered as scoped service, and each page has it's own scope, so you cannot just resolve it from application's services. you have to inject it directly into your page or viewmodel ctor.