Change to display Popup on Active Window page on Windows
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) orChampioned(feature/proposal) - [x] Has tests (if omitted, state reason in description)
- [ ] Has samples (if omitted, state reason in description)
- [x] Rebased on top of
mainat 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.
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.
It would be best if there was a way to determine which page is calling the Popup. . .
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.
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?