Skip to content

[Proposal] PopupService #981

@bijington

Description

@bijington

Feature name

PopupService

Link to discussion

#933

Progress tracker

  • Android Implementation
  • iOS Implementation
  • MacCatalyst Implementation
  • Windows Implementation
  • Tizen Implementation
  • Unit Tests
  • Samples
  • Documentation

Summary

The following proposal provides the ability to register and show popups with associated view models. It will also allow this to be done from a view model.

Motivation

To make it easier to show popups from a view model.

Detailed Design

PopupService

using System.ComponentModel;
using CommunityToolkit.Maui.Views;

namespace Popups;

public class PopupService
{
    private readonly IServiceProvider serviceProvider;

    private readonly static IDictionary<Type, Type> viewModelToViewMappings = new Dictionary<Type, Type>();

    public PopupService(IServiceProvider serviceProvider)
    {
        this.serviceProvider = serviceProvider;
    }

    public static void AddTransientPopup<TPopupView, TPopupViewModel>(IServiceCollection services)
        where TPopupView : Popup
        where TPopupViewModel : INotifyPropertyChanged
    {
        viewModelToViewMappings.Add(typeof(TPopupViewModel), typeof(TPopupView));

        services.AddTransient(typeof(TPopupView));
        services.AddTransient(typeof(TPopupViewModel));
    }

    public Task<object> ShowPopupAsync<TViewModel>()
    {
        var viewModelType = typeof(TViewModel);

        var viewModel = (TViewModel)this.serviceProvider.GetService<TViewModel>();

        if (viewModel is null)
        {
            throw new InvalidOperationException($"Unable to resolve type {viewModelType} please make sure that you have called RegisterPopup");
        }

        return ShowPopupAsync<TViewModel>(viewModel);
    }

    public Task<object> ShowPopupAsync<TViewModel>(TViewModel viewModel)
    {
        var viewModelType = typeof(TViewModel);

        var view = (Popup)this.serviceProvider.GetRequiredService(viewModelToViewMappings[viewModelType]);

        view.BindingContext = viewModel;

        // TODO: Do we need to provide an override for determine the main page? Or we at least need to verify there is a main page.
        return Application.Current.MainPage.ShowPopupAsync(view);
    }
}

ServiceCollectionExtension

public static class ServiceCollectionExtensions
{
    public static IServiceCollection AddTransientPopup<TPopupView, TPopupViewModel>(this IServiceCollection services)
        where TPopupView : Popup
        where TPopupViewModel : INotifyPropertyChanged
    {
        PopupService. AddTransientPopup<TPopupView, TPopupViewModel>(services);

        return services;
    }
}

Usage Syntax

// Registration in MauiProgram.cs
builder.Services.AddTransientPopup<ConfirmationPopupView, ConfirmationPopupViewModel>();

// Showing of popup from a VM
popupService.ShowPopupAsync<ConfirmationPopupViewModel>();

Drawbacks

It is heavily MVVM focused

Alternatives

No response

Unresolved Questions

No response

Metadata

Metadata

Assignees

Labels

approvedThis Proposal has been approved and is ready to be added to the ToolkitchampionA member of the .NET MAUI Toolkit core team has chosen to champion this featuredocumentation approvedproposalA fully fleshed out proposal describing a new feature in syntactic and semantic detail

Type

No type

Projects

Status

Completed

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions