Redigera

Dela via


Popup

Popups are a very common way of presenting information to a user that relates to their current task. Operating systems provide a way to show a message and require a response from the user, these alerts are typically restrictive in terms of the content a developer can provide and also the layout and appearance.

Note

If you wish to present something to the user that is more subtle then checkout our Toast and Snackbar options.

The Popup view allows developers to build their own custom UI and present it to their users.

Building a Popup

A Popup can be created in XAML or C#:

XAML

Including the XAML namespace

In order to use the toolkit in XAML the following xmlns needs to be added into your page or view:

xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"

Therefore the following:

<ContentPage
    x:Class="CommunityToolkit.Maui.Sample.Pages.MyPage"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">

</ContentPage>

Would be modified to include the xmlns as follows:

<ContentPage
    x:Class="CommunityToolkit.Maui.Sample.Pages.MyPage"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit">

</ContentPage>

Defining your Popup

Please note that if a Popup is created in XAML it must have a C# code behind file as well. To understand why this is required please refer to this .NET MAUI documentation page.

The easiest way to create a Popup is to add a new .NET MAUI ContentView (XAML) to your project and then change each of the files to the following:

<toolkit:Popup xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
               xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
               xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
               x:Class="MyProject.SimplePopup">

    <VerticalStackLayout>
        <Label Text="This is a very important message!" />
    </VerticalStackLayout>
    
</toolkit:Popup>
public partial class SimplePopup : Popup
{
    public SimplePopup()
    {
        InitializeComponent();
    }
}

Important

If the code behind file is not created along with the call to InitializeComponent then an exception will be thrown when trying to display your Popup.

C#

using CommunityToolkit.Maui.Views;

var popup = new Popup
{
    Content = new VerticalStackLayout
    {
        Children = 
        {
            new Label
            {
                Text = "This is a very important message!"
            }
        }
    }
};

Presenting a Popup

Once the Popup has been built it can then be presented through the use of our Popup extension methods or through the IPopupService implementation from this toolkit.

IPopupService

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 can now be driven by only providing the view model making it possible to keep a clean separation between view and view model.

Registering Popups

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.

Displaying Popups

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<UpdatingPopupViewModel>();
    }
}

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. The IPopupService makes this possible through the overloads of the ShowPopup and ShowPopupAsync methods that takes a Action<TViewModel> onPresenting parameter. This parameter has been designed to be framework agnostic and allow you as a developer to drive the loading/passing of data however best fits your architecture.

To extend the previous example of showing a UpdatingPopupViewModel and its associated Popup, we can use the onPresenting parameter to pass in the number of updates that we wish to perform:

public class MyViewModel : INotifyPropertyChanged
{
    private readonly IPopupService popupService;

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

    public void DisplayPopup()
    {
        this.popupService.ShowPopup<UpdatingPopupViewModel>(onPresenting: viewModel => viewModel.PerformUpdates(10));
    }
}

Extension methods

Important

A Popup can only be displayed from a Page or an implementation inheriting from Page.

using CommunityToolkit.Maui.Views;

public class MyPage : ContentPage
{
    public void DisplayPopup()
    {
        var popup = new SimplePopup();

        this.ShowPopup(popup);
    }
}

Closing a Popup

There are 2 different ways that a Popup can be closed; programmatically or by tapping outside of the popup.

Programmatically closing a Popup

In order to close a Popup a developer must call Close or CloseAsync on the Popup itself. This is typically performed by responding to a button press from a user.

We can enhance the previous XAML example by adding an OK Button:

<toolkit:Popup xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
               xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
               xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
               x:Class="MyProject.SimplePopup">

    <VerticalStackLayout>
        <Label Text="This is a very important message!" />
        <Button Text="OK" 
                Clicked="OnOKButtonClicked" />
    </VerticalStackLayout>
    
</toolkit:Popup>

In the resulting event handler we call Close, this will programmatically close the Popup.

Note

Close() is a fire-and-forget method. It will complete and return to the calling thread before the operating system has dismissed the Popup from the screen. If you need to pause the execution of your code until the operating system has dismissed the Popup from the screen, use instead CloseAsync().

public partial class MySimplePopup : Popup
{
    // ...

    void OnOKButtonClicked(object? sender, EventArgs e) => Close();
}

In the resulting event handler we call CloseAsync, this will programmatically close the Popup allowing the caller to await the method until the operating system has dismissed the Popup from the screen.

public partial class MySimplePopup : Popup
{
    // ...

    async void OnOKButtonClicked(object? sender, EventArgs e) 
    {
        var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));

         await CloseAsync(token: cts.Token);
         await Toast.Make("Popup Dismissed By Button").Show();
    }
}

Tapping outside of the Popup

By default a user can tap outside of the Popup to dismiss it. This can be controlled through the use of the CanBeDismissedByTappingOutsideOfPopup property. Setting this property to false will prevent a user from being able to dismiss the Popup by tapping outside of it.

Returning a result

A developer will quite often seek a response from their user, the Popup view allows developers to return a result that can be awaited for and acted on.

We can enhance our original XAML example to show how this can be accomplished:

XAML

By adding 2 new buttons to the XAML:

<toolkit:Popup xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
               xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
               xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
               x:Class="MyProject.SimplePopup">

    <VerticalStackLayout>
        <Label Text="This is a very important message! Do you agree?" />
        <Button Text="Yes" 
                Clicked="OnYesButtonClicked" />
        <Button Text="No"
                Clicked="OnNoButtonClicked" />
    </VerticalStackLayout>
    
</toolkit:Popup>

Then adding the following event handlers in the C#:

async void OnYesButtonClicked(object? sender, EventArgs e)
{
    var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
    await CloseAsync(true, cts.Token);
}

async void OnNoButtonClicked(object? sender, EventArgs e)
{
    var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
    await CloseAsync(false, cts.Token);
}

The Close method allows for an object value to be supplied, this will be the resulting return value. In order to await the result the ShowPopupAsync method must be used as follows:

using CommunityToolkit.Maui.Views;

public class MyPage : ContentPage
{
    public async Task DisplayPopup()
    {
        var popup = new SimplePopup();

        var result = await this.ShowPopupAsync(popup, CancellationToken.None);

        if (result is bool boolResult)
        {
            if (boolResult)
            {
                // Yes was tapped
            }
            else
            {
                // No was tapped
            }
        }
    }
}

Note

In order to handle the tapping outside of a Popup when also awaiting the result you can change the value that is returned through the ResultWhenUserTapsOutsideOfPopup property.

Styling

The Popup class allows the use of .NET MAUI Styles to make it easier to share common visual settings across multiple popups.

The following example shows how to define a style that applies to the SimplePopup example from the previous section.

<toolkit:Popup xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
               xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
               xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
               xmlns:popups="clr-namespace:CommunityToolkit.Maui.Sample.Views.Popups"
               x:Class="MyProject.SimplePopup">

    <toolkit:Popup.Resources>
        <Style TargetType="{x:Type popups:SimplePopup}">
            <Setter Property="Size" Value="100,200" />
            <Setter Property="Color" Value="Green" />
            <Setter Property="HorizontalOptions" Value="Center" />
            <Setter Property="VerticalOptions" Value="Start" />
            <Setter Property="CanBeDismissedByTappingOutsideOfPopup" Value="True" />
        </Style>
    </toolkit:Popup.Resources>

    <VerticalStackLayout>
        <Label Text="This is a very important message! Do you agree?" />
        <Button Text="Yes" 
                Clicked="OnYesButtonClicked" />
        <Button Text="No"
                Clicked="OnNoButtonClicked" />
    </VerticalStackLayout>
    
</toolkit:Popup>

Note

When creating a Style that targets Popup and you wish to make it apply to custom popups like the SimplePopup example, make sure to set the ApplyToDerivedTypes property on the Style definition.

Properties

Property Type Description
Anchor View Gets or sets the View anchor. The Anchor is where the Popup will render closest to. When an Anchor is configured the popup will appear centered over that control or as close as possible.
CanBeDismissedByTappingOutsideOfPopup bool Gets or sets a value indicating whether the popup can be dismissed by tapping outside of the Popup. On Android - when false the hardware back button is disabled.
Color Color Gets or sets the Color of the Popup. This color sets the native background color of the Popup, which is independent of any background color configured in the actual Content.
Content View Gets or sets the View content to render in the Popup.
HorizontalOptions LayoutAlignment Gets or sets the LayoutAlignment for positioning the Popup horizontally on the screen.
Result Task<object?> Gets the final result of the dismissed Popup.
Size Size Gets or sets the Size of the Popup Display. The Popup will always try to constrain the actual size of the Popup to the size of the View unless a Size is specified. If the Popup uses the HorizontalOptions or VerticalOptions properties that are not the defaults then this Size property is required.
VerticalOptions LayoutAlignment Gets or sets the LayoutAlignment for positioning the Popup vertically on the screen.

Events

Event Description
Closed Occurs when the Popup is closed.
Opened Occurs when the Popup is opened.

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.