-
Notifications
You must be signed in to change notification settings - Fork 439
Migrating to Popup v2
We recently shipped version 2 of the Popup in the .NET MAUI Community Toolkit.
This comes with a number of breaking changes but we promise that you are going to love the result!
We did try hard to make a seamless migration path however this was just not feasible. We experienced an overwhelming number of issues in the original popup implementation and made the hard decision to drop and replace it with something we believe will be much more stable.
The original implementation made use of platform specific implementations to show the popup (e.g. UIPopoverPresentationController
on iOS and macOS) while this worked well at the general presentation of a view it lead to many issues within our codebase aimed at dealing with layouts and sizing of the content - this is something that MAUI already does for us.
The sheer fact that the Pull Request introducing popup v2 closed 31 issues just goes to show the impact!
If you are in the process of migrating from v1 to v2 or are about to begin that journey the following article is aimed at helping.
We have moved IPopupService
from CommunityToolkit.Maui.Core
to CommunityToolkit.Maui
. You will likely need to update any using
statements in the files where you use IPopupService
from using CommunityToolkit.Maui.Core;
to using CommunityToolkit.Maui;
.
Yes we understand that this was a rather limited factor with the old implementation, thankfully the new approach makes it possible to show the same instance multiple times. This improvement was the influence behind the next improvement:
Now that popups can be displayed multiple times we have provided support for registering popups as singleton or scoped services.
You can now use any View
as the popup content without inheriting from Popup
. The only caveat to this rule is - if you need to return a result from the popup, you have to inherit from Popup
.
Popup
now inherits from ContentView
which provides similar properties to what had been added to the original Popup
implementation. In order to provide a much more consistent approach with how developers build their user interfaces we took the decision to shift over to the using the properties that come out of the box from .NET MAUI, therefore the following has been modified:
<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"
- Size="100,200"
+ WidthRequest="100"
+ HeightRequest="200">
</toolkit:Popup>
<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"
- Color="Green"
+ BackgroundColor="Green">
</toolkit:Popup>
This can now be controller by the PopupOptions
class.
Popup
s now have their content wrapped inside a Border
control making it easy to style without having to increase the complexity of your popup view.
This can now be controller by the PopupOptions
class.
When displaying a popup through the IPopupService
, Page
, Shell
or INavigation
, developers can now pass in options that customize the behavior and appearance of the displayed popup.
The original way of passing data through the onPresenting
parameter when calling IPopupService.Show
no longer exists. This has now been replaced by using the IQueryAttributable
interface that integrates with .NET MAUI Shell. You can use it just like you do with .NET MAUI Shell to Process navigation data using a single method. This change was made in order to provide a unified and therefore consistent way of passing navigation data around a .NET MAUI application.
Original way:
public class NamePopupViewModel : ObservableObject
{
[ObservableProperty]
string name = "";
}
public class MyViewModel : INotifyPropertyChanged
{
private readonly IPopupService popupService;
public MyViewModel(IPopupService popupService)
{
this.popupService = popupService;
}
public void DisplayPopup()
{
this.popupService.ShowPopup<NamePopupViewModel>(onPresenting: viewModel => viewModel.Name = "Shaun");
}
}
New way:
public class NamePopupViewModel : ObservableObject, IQueryAttributable
{
[ObservableProperty]
string name = "";
public void ApplyQueryAttributes(IDictionary<string, object> query)
{
Name = query["Name"] as string;
}
}
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>
{
["Name"] = "Shaun"
};
await this.popupService.ShowPopupAsync<NamePopupViewModel>(
Shell.Current,
options: null,
queryAttributes);
}
}