user-interfacemaui

How to make a modal Window in MAUI


I'm learning .NET MAUI for a course and stumbled upon this problem while trying to have the "Registration Form" pop up from the main window. And I've found no clean way to make the form pops up like other frameworks or libraries.

I did manage to open a Window - it isn't hard to find - but the opened Window isn't up to my expectation of a "Modal Window". I expect the same behaviour as wxDialog shown with ShowModal, which is

  1. Pops the window open.
  2. Blocks the parent window.
  3. Closes with the parent window.

I've tried what the documentation at Microsoft Learn was saying - Application.Current?.OpenWindow(wnd);. Except:

  1. It doesn't block the "parent" (in quote) window and
  2. It doesn't close with the "parent"
  3. It doesn't have the title bar (the one that displays your page's Title)

I was experimenting around with that approach but so far I've only managed to make the title bar appear:

#if WINDOWS
        var page = new NavigationPage(new RegistrationPage());
        var wnd = new Window(page);
        wnd.Width = 720;
        wnd.Height = 440;
        Application.Current?.OpenWindow(wnd);
#else
        await Shell.Current.GoToAsync(nameof(RegistrationPage), true);
#endif

Or wrapping it in a Shell:

#if WINDOWS
        var shell = new Shell();
        shell.Items.Add(new ShellContent { ContentTemplate = new DataTemplate(() => new RegistrationPage()) });
        var wnd = new Window(shell);
        wnd.Width = 720;
        wnd.Height = 440;
        Application.Current?.OpenWindow(wnd);
#else
        await Shell.Current.GoToAsync(nameof(RegistrationPage), true);
#endif

Which I approximated from the AppShell.xaml, and it also works, and I quite like it. But some GenAIs tell me to use NavigationPage to achieve the same result. But the title text for that approach is white, not purple, like the Shell way...

I think there ought to be some event for creation/destruction? But am I the one who's supposed to wire parent-child windows toghether? I get that the "parent" doesn't get recognised because it was never mentioned anywhere in the process (Application.Current jumps straight into OpenWindow) but it doesn't seems like Window can open Window either.

I was about to try subclassing something to make it works, but

  1. I don't know what to subclass? My whole experience with UI came from wxFormBuilder. Or something much simpler like TKinter. And the App-Shell-Window-Page-View thing is confusing.
  2. Am I going down to platform-specific APIs to do this? I only know so much about Windows; probably enough to do this. I'm not even sure.
  3. Should I do that? When it comes to modal in MAUI, what I see most of the time is the modal get pushed onto the page and cover it. It'd work cross-platform, I think. But my personal preference is to have it pop out.
  4. And is it worth to roll a subclass for this?

I've also thought about having a bookkeeping class, but haven't committed to it.

tl;dr very confused.


Solution

  • First of all, you do not have to use NavigationPage.
    You will end up using PushModalAsync. And this is not relevant to Navigation / Shell differences.

    You can push modal pages in Shell, with something like:
    await Navigation.PushModalAsync(new MyContentPage());

    (Or request a construction from the DI, use some sort of factory - irrelevant to what I am saying.)

    The content page background can be set to transparent, or to semi-transparent, and inside you can put some nice round border for bubble popup, text, picture and so on, that you can pass to the popup etc.

    There are some "settings" for mobiles, like over the whole screen for IOS, or how it can be closed for android. You can also choose to play animation or not when popping up/out.

    No need for CommunityToolkit. No need for switching to NavigationPage. All this is built into MAUI.

    Now, the following is somewhat opinion based:

    Just because I can do a modal page in MAUI, it doesn't mean I would. The Shell navigation is as "modal" as anything can get.

    You should be controlling what is inside the navigation stack, not try to lock in the user to some modal page.

    Everything that is inside your Shell xaml, you can have as root. And the rest goes as registered route to your shell.

    So one way to do a typical login-registration flow is to have the LoginPage as root. And registration page as route. The rest of your application goes under the LoginPage position in the Shell xaml.

    The application starts, the first position of the shell opens - that is your login page. You can open "registration" by clicking a button. Then go back to login page.

    Nothing else in the stack. So the user cannot leave this, without you calling GoToAsync.