Maui icon indicating copy to clipboard operation
Maui copied to clipboard

Change to display Popup on Active Window page on Windows

Open cat0363 opened this issue 2 years ago • 4 comments

This PR resolves the issue where popups are not displayed on the active window page on Windows.

Description of Change

To get the active windows in Windows, look for each window whose IsActivated property is true in Application.Current.Windows. Call the ShowPopup and ShowPopupAsync methods on the active window page. Below are the changes.

[src\CommunityToolkit.Maui\PopupService.cs]

public void ShowPopup<TViewModel>() where TViewModel : INotifyPropertyChanged
{
    var popup = GetPopup(typeof(TViewModel));

    ValidateBindingContext<TViewModel>(popup, out _);

#if WINDOWS
    Application.Current!.Windows.First(x => x.IsActivated).Page!.ShowPopup(popup);
#else
    CurrentPage.ShowPopup(popup);
#endif
}

public void ShowPopup<TViewModel>(TViewModel viewModel) where TViewModel : INotifyPropertyChanged
{
    ArgumentNullException.ThrowIfNull(viewModel);

    var popup = GetPopup(typeof(TViewModel));

    ValidateBindingContext<TViewModel>(popup, out _);

#if WINDOWS
    Application.Current!.Windows.First(x => x.IsActivated).Page!.ShowPopup(popup);
#else
    CurrentPage.ShowPopup(popup);
#endif
}

public void ShowPopup<TViewModel>(Action<TViewModel> onPresenting) where TViewModel : INotifyPropertyChanged
{
    ArgumentNullException.ThrowIfNull(onPresenting);

    var popup = GetPopup(typeof(TViewModel));

    ValidateBindingContext(popup, out TViewModel viewModel);

    onPresenting.Invoke(viewModel);

#if WINDOWS
    Application.Current!.Windows.First(x => x.IsActivated).Page!.ShowPopup(popup);
#else
    CurrentPage.ShowPopup(popup);
#endif
}

public Task<object?> ShowPopupAsync<TViewModel>(CancellationToken token = default) where TViewModel : INotifyPropertyChanged
{
    var popup = GetPopup(typeof(TViewModel));

    ValidateBindingContext<TViewModel>(popup, out _);

#if WINDOWS
    return Application.Current!.Windows.First(x => x.IsActivated).Page!.ShowPopupAsync(popup, token);
#else
    return CurrentPage.ShowPopupAsync(popup, token);
#endif
}

public Task<object?> ShowPopupAsync<TViewModel>(TViewModel viewModel, CancellationToken token = default) where TViewModel : INotifyPropertyChanged
{
    ArgumentNullException.ThrowIfNull(viewModel);

    var popup = GetPopup(typeof(TViewModel));

    ValidateBindingContext<TViewModel>(popup, out _);

#if WINDOWS
    return Application.Current!.Windows.First(x => x.IsActivated).Page!.ShowPopupAsync(popup, token);
#else
    return CurrentPage.ShowPopupAsync(popup, token);
#endif
}

Linked Issues

  • Fixes #1616

PR Checklist

  • [x] Has a linked Issue, and the Issue has been approved(bug) or Championed (feature/proposal)
  • [x] Has tests (if omitted, state reason in description)
  • [ ] Has samples (if omitted, state reason in description)
  • [x] Rebased on top of main at time of PR
  • [x] Changes adhere to coding standard
  • [ ] Documentation created or updated: https://github.com/MicrosoftDocs/CommunityToolkit/pulls

Additional information

Below are the verification results.

https://github.com/CommunityToolkit/Maui/assets/125236133/ccaadede-f21a-4351-b6d2-a3c53a1339ee

You can see that the Popup is displayed in the active window.

cat0363 avatar Dec 21 '23 09:12 cat0363

In cases where a popup is displayed by setting a timer, it will not be displayed intentionally. . . In such cases, the active window may change from the Popup's caller until the Popup is displayed. If you need to consider such cases, please discard this PR.

cat0363 avatar Dec 21 '23 09:12 cat0363

It would be best if there was a way to determine which page is calling the Popup. . .

cat0363 avatar Dec 21 '23 09:12 cat0363

Perhaps to solve this problem we need some variation of Popup's ShowPopup, ShowPopupAsync methods that pass an instance of the page we want to display. If you use the current page, the problem I previously described will occur.

cat0363 avatar Jan 19 '24 02:01 cat0363

I am just wondering if we could opt for registering the PopupService as scoped given .NET MAUI scopes per window, then we could somehow obtain the active window at the time of resolution and rely on that through the life of the PopupService instance. What do people think?

bijington avatar Feb 26 '24 20:02 bijington