Edit

Share via


PopupService

The PopupService provides a mechanism for displaying Popups within an application using the MVVM pattern.

The following sections will incrementally build on how to use the PopupService in a .NET MAUI application.

Creating a Popup

In order to use the PopupService to present or close a Popup the Popup must first be registered. Based on the steps in Displaying a Popup the following can be created.

The XAML contents of the Popup can be defined as:

<ContentView
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:viewModels="clr-namespace:MyProject.ViewModels"
    x:Class="MyProject.Popups.NamePopup"
    HorizontalOptions="Center"
    VerticalOptions="Center"
    Padding="10"
    Spacing="6"
    x:DataType="viewModels:NamePopupViewModel">

    <VerticalStackLayout>
        <Label Text="What is your name?" />
        <Entry Text="{Binding Name}" />

        <Button Text="Save" Command="{Binding SaveCommand}" />
        <Button Text="Cancel" Command="{Binding CancelCommand}" />
    </VerticalStackLayout>
    
</ContentView>

The C# contents of the Popup can be defined as:

using MyProject.ViewModels;

namespace MyProject.Popups;

public partial class NamePopup : ContentView
{
    public NamePopup(NamePopupViewModel namePopupViewModel)
    {
        InitializeComponent();
        BindingContext = namePopupViewModel;
    }
}

The backing view model for the Popup can be defined as:

public class NamePopupViewModel : ObservableObject
{
    [ObservableProperty]
    public partial string Name { get; set; } = string.Empty;

    readonly IPopupService popupService;

    public NamePopupViewModel(IPopupService popupService)
    {
        this.popupService = popupService;
    }

    void OnCancel()
    {
    }

    [RelayCommand(CanExecute = nameof(CanSave))]
    void OnSave()
    {
    }

    bool CanSave() => string.IsNullOrWhitespace(Name) is false;
}

Registering a Popup

In order to first use the IPopupService to display a popup in your application you will need to register the popup and view model with the MauiAppBuilder, this can be done through the use of Register Popup View and View Model.

Based on the example above the following code can be added to the MauiProgram.cs file.

builder.Services.AddTransientPopup<NamePopup, NamePopupViewModel>();

Presenting a Popup

The .NET MAUI Community Toolkit provides a mechanism to instantiate and present popups in a .NET MAUI application. The popup service is automatically registered with the MauiAppBuilder when using the UseMauiCommunityToolkit initialization method. This enables you to resolve an IPopupService implementation in any part of your application.

The IPopupService makes it possible to register a popup view and its associated view model. The ability to show a Popup requires a developer to pass in the current INavigation implementation for the current window in the application. The easiest way to achieve this is through the following example.

The following example shows how to use the IPopupService to create and display a popup in a .NET MAUI application:

public class MyViewModel : INotifyPropertyChanged
{
    private readonly IPopupService popupService;

    public MyViewModel(IPopupService popupService)
    {
        this.popupService = popupService;
    }

    public void DisplayPopup()
    {
        this.popupService.ShowPopup<NamePopupViewModel>(Shell.Current);
    }
}

Alternatively the caller can await the ShowPopupAsync method in order to handle a result being returned. The DisplayPopup method can be rewritten as:

public async Task DisplayPopup()
{
    var result = await this.popupService.ShowPopupAsync<NamePopupViewModel>(currentPage.Navigation);
}

For a more concrete example please refer to our sample application and the example in MultiplePopupViewModel

The IPopupService also provides methods to handle a result being returned from a Popup as covered in Returning a result.

Passing data to a Popup view model

When presenting a Popup we sometimes need to pass data across to the underlying view model to allow for dynamic content to be presented to the user. IPopupService makes this possible through the overloads of the ShowPopup and ShowPopupAsync methods that takes a IDictionary<string, object> shellParameters parameter. This makes use of the IQueryAttributable interface provided with .NET MAUI Shell, for more information on using this please refer to Process navigation data using a single method.

To extend the previous example of showing a NamePopupViewModel and its associated Popup, we can extend the NamePopupViewModel to implement the IQueryAttributable interface as follows:

public class NamePopupViewModel : ObservableObject, IQueryAttributable
{
    [ObservableProperty]
    public partial string Name { get; set; } = "";

    public void ApplyQueryAttributes(IDictionary<string, object> query)
    {
        Name = (string)query[nameof(NamePopupViewModel.Name)];
    }
}

Then the view model that presents the popup and passes the data can look as follows:

public class MyViewModel : INotifyPropertyChanged
{
    private readonly IPopupService popupService;

    public MyViewModel(IPopupService popupService)
    {
        this.popupService = popupService;
    }

    public async Task DisplayPopup()
    {
        var queryAttributes = new Dictionary<string, object>
        {
            [nameof(NamePopupViewModel.Name)] = "Shaun"
        };

        await this.popupService.ShowPopupAsync<NamePopupViewModel>(
            Shell.Current,
            options: PopupOptions.Empty,
            shellParameters: queryAttributes);
    }
}

Closing a Popup

The PopupService provides the ClosePopupAsync method that makes it possible to close a Popup from a view model.

Programmatically closing a Popup

Expanding on the previous example the following implementation can be added to the OnCancel method:

[RelayCommand]
async Task OnCancel()
{
    await popupService.ClosePopupAsync(Shell.Current);
}

This will result in the most recently displayed Popup being closed.

Returning a result

When closing a Popup it is possible to return a result to the caller that presented the Popup.

Expanding on the previous example the following implementation can be added to the OnSave method:

[RelayCommand(CanExecute = nameof(CanSave))]
async Task OnSave()
{
    await popupService.ClosePopupAsync(Shell.Current, Name);
}

This will result in the most recently displayed Popup being closed and the caller being return the value in Name wrapped inside of an IPopupResult<T> implementation. For more information on creating a Popup that can return a result see Popup - Returning a result.

Examples

You can find an example of this feature in action in the .NET MAUI Community Toolkit Sample Application.

API

You can find the source code for Popup over on the .NET MAUI Community Toolkit GitHub repository.

Additional Resources