Replies: 6 comments 23 replies
-
No you can't. The new Popup is your only option. What are the quirks? |
Beta Was this translation helpful? Give feedback.
-
The lack of Anchor is enough. There were other compiler errors, which were not immediately addressable (maybe they can be addressed, but maybe not). In any case, without an Anchor, I won't take a second look at this new popup. |
Beta Was this translation helpful? Give feedback.
-
If you want to use CommunityToolkit.Maui 12.x and CommunityToolkit.Maui 11.x at the same time, I suppose you could fork the CommunityToolkit.Maui 11.x code and change the namespace, to, say, CommunityToolkit11.Maui then you should be able to use both code bases at the same time. |
Beta Was this translation helpful? Give feedback.
-
Here is a basic PopupCompatible and PopupCompatibleExtensions class that mimics MCT v11 popup. If it's useful, I can wrap it up in a NuGet package. This may be enough to help run your existing code whilst migrating to MCT v12. using Microsoft.Maui.Controls.Shapes;
using SQuan.Helpers.Maui.Mvvm;
public partial class PopupCompatible : ContentView
{
[BindableProperty] public partial VisualElement? Anchor { get; set; }
[BindableProperty] public partial Color Color { get; set; } = Colors.Transparent;
[BindableProperty] public partial bool CanBeDismissedByTappingOutsideOfPopup { get; set; } = true;
ContentPage? page;
Grid? outsideOfPopupContainer;
BoxView? scrim;
Grid? popupContainer;
TaskCompletionSource<object?> tcs = new();
public async Task CloseAsync(object? result = null)
{
if (page is not null && page.Content is Grid pageGrid && pageGrid is not null && outsideOfPopupContainer is not null)
{
await pageGrid.Dispatcher.DispatchAsync(async () =>
{
if (popupContainer is not null)
{
await popupContainer.ScaleTo(0, 100, Easing.CubicIn);
}
pageGrid.Remove(outsideOfPopupContainer);
outsideOfPopupContainer = null;
});
tcs.SetResult(result);
}
}
public async Task<object?> ShowPopupAsync(ContentPage page)
{
if (page.Content is not Grid pageGrid)
{
pageGrid = new Grid();
if (page.Content is not null)
{
pageGrid.Add(page.Content);
}
page.Content = pageGrid;
}
tcs = new();
this.page = page;
outsideOfPopupContainer = new Grid();
outsideOfPopupContainer.Add(scrim = new BoxView() { BackgroundColor = Colors.Black, Opacity = 0.2 });
pageGrid.Add(outsideOfPopupContainer);
if (CanBeDismissedByTappingOutsideOfPopup)
{
var outsideOfPopup = new Button()
{
BackgroundColor = Colors.Transparent,
CornerRadius = 0,
Command = new Command(async () => await CloseAsync())
};
outsideOfPopupContainer.Add(outsideOfPopup);
}
popupContainer = new Grid()
{
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center,
};
popupContainer.Add(new Border()
{
BackgroundColor = Color,
Stroke = Colors.LightGray,
StrokeThickness = 1,
StrokeShape = new RoundRectangle()
{
CornerRadius = 10
}
});
popupContainer.Add(new ContentView() { Padding = 20, Content = this });
popupContainer.Scale = 0;
Task<bool> scaleToTask = popupContainer.ScaleTo(1, 100, Easing.CubicOut);
outsideOfPopupContainer.Add(popupContainer);
if (Anchor is VisualElement anchor && anchor is not null)
{
var anchorPoint = GetAbsolutePosition(anchor);
popupContainer.HorizontalOptions = LayoutOptions.Start;
popupContainer.VerticalOptions = LayoutOptions.Start;
popupContainer.TranslationX = anchorPoint.X + anchor.Width / 2 - popupContainer.Width / 2;
bool anchorAtBottom = anchorPoint.Y + anchor.Height + 10 + popupContainer.Height < page.Height;
if (anchorAtBottom)
{
popupContainer.TranslationY = anchorPoint.Y + anchor.Height + 10;
}
else
{
popupContainer.TranslationY = anchorPoint.Y - 10 - popupContainer.Height;
}
anchor.PropertyChanged += (s, e) =>
{
if (e.PropertyName == nameof(VisualElement.Width))
{
anchorPoint = GetAbsolutePosition(anchor);
popupContainer.TranslationX = anchorPoint.X + anchor.Width / 2 - popupContainer.Width / 2;
}
};
popupContainer.PropertyChanged += (s, e) =>
{
switch (e.PropertyName)
{
case nameof(PopupCompatible.Width):
anchorPoint = GetAbsolutePosition(anchor);
popupContainer.TranslationX = anchorPoint.X + anchor.Width / 2 - popupContainer.Width / 2;
break;
case nameof(PopupCompatible.Height):
anchorPoint = GetAbsolutePosition(anchor);
anchorAtBottom = anchorPoint.Y + anchor.Height + 10 + popupContainer.Height < page.Height;
if (anchorAtBottom)
{
popupContainer.TranslationY = anchorPoint.Y + anchor.Height + 10;
}
else
{
popupContainer.TranslationY = anchorPoint.Y - 10 - popupContainer.Height;
}
break;
}
};
}
await scaleToTask;
return await tcs.Task;
}
public static Point GetAbsolutePosition(VisualElement visualElement)
{
var pos = new Point();
while (visualElement is not null)
{
pos.X += visualElement.X;
pos.Y += visualElement.Y;
if (visualElement is ScrollView scrollView)
{
pos.X -= scrollView.ScrollX;
pos.Y -= scrollView.ScrollY;
}
if (visualElement.Parent is VisualElement parent)
{
visualElement = parent;
continue;
}
break;
}
return pos;
}
}
public static class PopupCompatibleExtensions
{
public static async Task<object?> ShowPopupAsync(this ContentPage page, PopupCompatible popup)
{
return await popup.ShowPopupAsync(page);
}
} Here's a sample usage where I can invoke the old style and new style popup in the same source: using CommunityToolkit.Maui.Extensions;
using CommunityToolkit.Maui.Views;
public partial class MainPage : ContentPage
{
int count = 0;
public MainPage()
{
InitializeComponent();
}
async void OnCounterClicked(object? sender, EventArgs e)
{
count++;
if (count == 1)
CounterBtn.Text = $"Clicked {count} time";
else
CounterBtn.Text = $"Clicked {count} times";
SemanticScreenReader.Announce(CounterBtn.Text);
await Task.Delay(1);
#region Demo of old PopupCompatible
var oldPopup = new PopupCompatible()
{
Anchor = CounterBtn,
Color = Colors.SkyBlue,
CanBeDismissedByTappingOutsideOfPopup = true,
};
oldPopup.Content = new Button
{
Text = "Close from PopupCompatible",
Command = new Command(async () => await oldPopup.CloseAsync("close"))
};
object? result = await this.ShowPopupAsync(oldPopup);
System.Diagnostics.Debug.WriteLine($"Popup result: {result}");
#endregion
#region Demo of new CommunityToolkit.Maui Popup
var newPopup = new Popup<string>()
{
BackgroundColor = Colors.SkyBlue,
CanBeDismissedByTappingOutsideOfPopup = true,
};
newPopup.Content = new Button
{
Text = "Close from CommunityToolkit.Maui v 12",
Command = new Command(async () => await newPopup.CloseAsync("close"))
};
var r = await this.ShowPopupAsync<string>(newPopup);
System.Diagnostics.Debug.WriteLine($"Popup result: {r.Result} WasDismissedByTappingOutsideOfPopup={r.WasDismissedByTappingOutsideOfPopup}");
#endregion
}
} Sample GitHub repo: https://github.com/stephenquan/MauiMCTMigration |
Beta Was this translation helpful? Give feedback.
-
@pictos I can't remember how the v11 anchoring actually works, but, I patched the code sample above to try to account for anchoring either top or bottom based on available space. |
Beta Was this translation helpful? Give feedback.
-
One more issue with the new popup is that when it is closed, the parent page (the one from which the popup was displayed) is activated, triggering OnAppearing of that page. This means that if the popup is shown from OnAppearing (directly or indirectly), OnAppearing gets called again, leading to a loop. The problem is that a popup can be shown by some library, and the author of the code of OnAppearing won't even know about this behavior. And even knowing about it, one would have to add some quirky workarounds to all pages that do something in OnAppearing. And no need to say that the parent page does not visually disappear when the popup is shown (although it does receive a call to OnDisappearing), so this disappearing/appearing sequence is quite unnatural. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
The new popup implementation is missing the Anchor property and has other quirks that make it impossible to use as a replacement of the old popup class, and this is a huge problem for my application.
The question is - as I don't care about 30+ issues in the old popup closed with the new one, can I combine the old popup with the new version of CommunityToolkit.MAUI? Did anybody do this successfully?
Beta Was this translation helpful? Give feedback.
All reactions