Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/maui/TOC.yml
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,10 @@ items:
href: views/Popup.md
- name: "Popup Service"
href: views/popup-service.md
- name: "Customizing Popup behavior and appearance"
href: views/popup/popup-options.md
- name: "Returning a value from a Popup"
href: views/popup/popup-result.md
- name: SemanticOrderView
href: views/semantic-order-view.md
- name: C# Markup
Expand Down
228 changes: 55 additions & 173 deletions docs/maui/views/Popup.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,37 +14,39 @@ Popups are a very common way of presenting information to a user that relates to

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

The .NET MAUI Community Toolkit provides 2 approaches to create a `Popup` that can be shown in a .NET MAUI application. These approaches will depend on the use case. This page focuses on the simplest form of `Popup` - simply rendering an overlay in an application, for the more advanced approach enabling the ability to return a result from the `Popup` please refer to [Popup - Returning a result](./popup/popup-result.md).

## Building a Popup

A `Popup` can be created in XAML or C#:
A `Popup` can be created in XAML or C# as follows:

### XAML

#### Including the XAML namespace

[!INCLUDE [XAML usage guidance](../includes/xaml-usage.md)]
The following section covers how to create a `Popup` using XAML.

#### 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](/dotnet/maui/xaml/runtime-load).

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:
The easiest way to create a `Popup` is to add a new `.NET MAUI ContentView (XAML)` to your project, this will create 2 files; a _*.xaml_ file and a _*.xaml.cs_ file. The contents of each file can be replaced with the following:

##### .xaml

```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!" />
</VerticalStackLayout>
<ContentView
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MyProject.SimplePopup">

<Label Text="This is a very important message!" />

</toolkit:Popup>
</ContentView>
```

##### .xaml.cs

```csharp
public partial class SimplePopup : Popup
public partial class SimplePopup : ContentView
{
public SimplePopup()
{
Expand All @@ -58,30 +60,25 @@ public partial class SimplePopup : Popup

### C#

The following section covers how to create a `Popup` using C#.

```csharp
using CommunityToolkit.Maui.Views;

var popup = new Popup
var popup = new ContentView
{
Content = new VerticalStackLayout
Content = new Label
{
Children =
{
new Label
{
Text = "This is a very important message!"
}
}
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`](popup-service.md) implementation from this toolkit.
Once the `Popup` has been built it can then be presented through the use of the `Popup` extension methods used on a `Page`, `Shell` or an `INavigation`, or through the [`IPopupService`](popup-service.md) implementation from this toolkit.

> [!IMPORTANT]
> A `Popup` can only be displayed from a `Page` or an implementation inheriting from `Page`.
The following example shows how to instantiate and show the `SimplePopup` created in the previous example through a method on a `ContentPage`.

```csharp
using CommunityToolkit.Maui.Views;
Expand All @@ -103,43 +100,44 @@ There are 2 different ways that a `Popup` can be closed; programmatically or by

### 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.
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 or once a long running task has completed.

We can enhance the previous XAML example by adding an **OK** `Button`:
To show how a `Popup` can be closed programmatically, the `SimplePopup` XAML example can be enhanced by:

```xml
<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">
- changing the `ContentView` element to `VerticalStackLayout`
- adding an **OK** `Button`

<VerticalStackLayout>
<Label Text="This is a very important message!" />
<Button Text="OK"
Clicked="OnOKButtonClicked" />
</VerticalStackLayout>
```xaml
<VerticalStackLayout
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MyProject.SimplePopup">

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

</toolkit:Popup>
</VerticalStackLayout>
```

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()`.
In the resulting event handler `OnOKButtonClicked` we call `Close`, this will programmatically close the `Popup`.

```csharp
public partial class MySimplePopup : Popup
public partial class SimplePopup : VerticalStackLayout
{
// ...

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.
> [!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()`.

Alternatively in the resulting event handler `OnOKButtonClicked` 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.

```csharp
public partial class MySimplePopup : Popup
public partial class SimplePopup : VerticalStackLayout
{
// ...

Expand All @@ -155,143 +153,27 @@ public partial class MySimplePopup : Popup

### 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:

```xml
<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#:

```csharp
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:

```csharp
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](/dotnet/maui/user-interface/styles/xaml) 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.

```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"
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`](/dotnet/api/microsoft.maui.controls.style.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. |
By default a user can tap outside of the `Popup` to dismiss it. This can be controlled through the use of the `PopupOptions.CanBeDismissedByTappingOutsideOfPopup` property. Setting this property to `false` will prevent a user from being able to dismiss the `Popup` by tapping outside of it. See [PopupOptions](./popup/popup-options.md) for more details.

## Events

The `Popup` class provides the following events that can be subscribed to.

|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](https://github.com/CommunityToolkit/Maui/blob/main/samples/CommunityToolkit.Maui.Sample/Pages/Views/).
You can find an example of this feature in action in the [.NET MAUI Community Toolkit Sample Application](https://github.com/CommunityToolkit/Maui/blob/main/samples/CommunityToolkit.Maui.Sample/Pages/Views/Popup/).

## API

You can find the source code for `Popup` over on the [.NET MAUI Community Toolkit GitHub repository](https://github.com/CommunityToolkit/Maui/tree/main/src/CommunityToolkit.Maui/Views/Popup).

## Additional Resources

- [`IPopupService`](popup-service.md)
- [`Popup` - Returning a result](./popup/popup-result.md)
- [`PopupOptions` - Customizing a `Popup` behavior and appearance](./popup/popup-options.md)
Loading