Search code examples
c#xamlmvvmmaui.net-maui

Custom pop-up template


I have been trying to create different kind of pop-ups to test how everything is working. I have went through documentation (https://learn.microsoft.com/en-us/dotnet/maui/user-interface/pop-ups), but there is no official example how to create a custom template for pop-ups or dialog boxes.

Lets say I would like to have on pop-up:

  • Label
  • DatePicker
  • TimePicker
  • TextBox
  • FilePicker
  • etc

and not only question and two answers or input field, as in Microsoft's examples.

Can somebody help with an example how I can create same looking pop-ups as default ones, but with custom set of controls that will utilize MVVM model?

For same looking, I mean this default layout:

enter image description here

I have tried to create custom layout this way, but there are many open questions how to template it to look as default one. Maybe there is a better way to do it?

NewAppointment.xaml:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="App.Controls.Popups.NewAppointmentPage"
             Title="NewAppointmentPage">
  <ContentPage.Content>
    <StackLayout VerticalOptions="Center" HorizontalOptions="Center">
      <Frame VerticalOptions="Center" CornerRadius="20" BackgroundColor="White">
        <StackLayout Padding="50,50,50,50">
          <ContentView x:Name="ContentView"/>
          <StackLayout Orientation="Horizontal">
            <Button Text="Confirm"></Button>
            <Button Text="Cancel"></Button>
          </StackLayout>
        </StackLayout>
      </Frame>
    </StackLayout>
  </ContentPage.Content>
</ContentPage>

NewAppointment.xaml.cs:

using System.Windows.Input;

namespace App.Controls.Popups;

public partial class NewAppointmentPage : ContentPage
{
  public NewAppointmentPage()
  {
    InitializeComponent();
    this.BackgroundColor = Color.FromArgb("#80000000");
  }

  public static readonly BindableProperty PopupContentProperty = BindableProperty.Create(
      propertyName: nameof(PopupContent),
      returnType: typeof(View),
      declaringType: typeof(NewAppointmentPage),
      defaultValue: null,
      defaultBindingMode: BindingMode.OneWay,
      propertyChanged: PopupContentPropertyChanged);

  private static void PopupContentPropertyChanged(BindableObject bindable, object oldValue, object newValue)
  {
    NewAppointmentPage controls = (NewAppointmentPage)bindable;
    if (newValue != null)
      controls.ContentView.Content = (View)newValue;
  }

  private bool IsVisible;

  public View PopupContent
  {
    get => (View)GetValue(PopupContentProperty);
    set { SetValue(PopupContentProperty, value); }
  }

  public ICommand PopModelCommand => new Command(async () =>
  {
    await App.Current.MainPage.Navigation.PopModalAsync();
  });
}

Then in HomeViewModel.cs:

private async void AddNewRecord()
{
  await App.Current.MainPage.Navigation.PushModalAsync(new NewAppointmentPage());
}

Solution

  • Using MAUI community toolkit you can create "custom popups"

    Here is an example (Pago_OK.xaml):

    <?xml version="1.0" encoding="utf-8" ?>
    <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="AppRipsaPagosMAUI.Pages.Helpers.Pago_OK"
                 CanBeDismissedByTappingOutsideOfPopup ="False">
        <VerticalStackLayout>
            <Label 
                Text="Payment finished"
                VerticalOptions="Center" 
                HorizontalOptions="Center" />
            <Label 
                Text="Insert your mail to get a ticket"
                VerticalOptions="Center" 
                HorizontalOptions="Center" />
            <Entry Placeholder="Insert your Mail"
                   x:Name="entryEmail" />
            <Button ImageSource="mail.png"
                    Clicked="OnEmailButtonClicked" /> 
            <Button Text="Finalizar" 
                    Clicked="OnYesButtonClicked" />
        </VerticalStackLayout>
    </toolkit:Popup>
    

    Pago_OK.xaml.cs

    public partial class Pago_OK 
    {
        
    
        public Pago_OK(DataToSend dataToSend)
        {
            InitializeComponent();
            /*some logic*/
            _pagosService = new PagosService(new HttpClient());     
        }
    
        async void OnEmailButtonClicked(object? sender, EventArgs e)
        {
            if (_cls_DevolucionPagos != null)
            {
                if (Email.Default.IsComposeSupported)
                {
                    string recipient = entryEmail.Text;
    
                    await _pagosService.SendEmail();
                }
            }     
            this.Close();
            await Shell.Current.Navigation.PopToRootAsync();
        }
    
        async void OnYesButtonClicked(object? sender, EventArgs e) => await Shell.Current.Navigation.PopToRootAsync();
    
    }
    

    And you call the popup like this:

    await Shell.Current.ShowPopupAsync(new Pago_OK(dataToSend));
    

    Remember that you can have a PopupViewModel inside it, and you can edit the popup as a custom page. Hope it helps!