Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Workaround WinUI bug with adding/removing flyouts #14985

Merged
merged 1 commit into from Jun 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -30,9 +30,11 @@
<FlyoutBase.ContextFlyout>
<MenuFlyout>
<MenuFlyoutItem Text="Add top-level menu items" Clicked="OnAddMenuClicked"></MenuFlyoutItem>
<MenuFlyoutSubItem Text="Sub menu items go in here">
<MenuFlyoutSubItem Text="Sub menu items go in here" x:Name="subMenu">
<MenuFlyoutItem Text="Add sub menu items below here" Clicked="OnAddSubMenuClicked"></MenuFlyoutItem>
<MenuFlyoutSeparator />
<MenuFlyoutSeparator />
<MenuFlyoutItem Text="Remove sub menu item above here" Clicked="OnRemoveSubMenuClicked" x:Name="removeSubMenuItems" IsEnabled="False"></MenuFlyoutItem>
</MenuFlyoutSubItem>
</MenuFlyout>
</FlyoutBase.ContextFlyout>
Expand Down
Expand Up @@ -150,18 +150,48 @@ void OnAddMenuClicked(object sender, EventArgs e)
void OnAddSubMenuClicked(object sender, EventArgs e)
{
var subMenu = (MenuFlyoutSubItem)((MenuFlyoutItem)sender).Parent;
AddNewMenu(subMenu, "sub-menu");
AddNewMenu(subMenu, "sub-menu", subMenu.Count - 2, subMenu.Count % 2 == 0);
CheckSubMenu();
}
void OnRemoveSubMenuClicked(object sender, EventArgs e)
{
var subMenu = (MenuFlyoutSubItem)((MenuFlyoutItem)sender).Parent;
subMenu.RemoveAt(subMenu.Count - 3);
CheckSubMenu();
}

private void AddNewMenu(IList<IMenuElement> parent, string newItemType)
void CheckSubMenu()
{
removeSubMenuItems.IsEnabled = subMenu.Count > 4;
}

private void AddNewMenu(IList<IMenuElement> parent, string newItemType, int index = -1, bool subMenuItem = false)
{
var newItemLocalValue = newMenuItemCount;
var newMenuItem = new MenuFlyoutItem() { Text = $"New {newItemType} menu item #{newItemLocalValue}" };
newMenuItem.Clicked += (s, e) => DisplayAlert(
IMenuElement newMenuItem;
MenuFlyoutItem mfi = new MenuFlyoutItem() { Text = $"New {newItemType} menu item #{newItemLocalValue}" };

mfi.Clicked += (s, e) => DisplayAlert(
title: "New Menu Item Click",
message: $"The new menu item {newItemLocalValue} was clicked",
cancel: "OK");
parent.Add(newMenuItem);

if (!subMenuItem)
{
newMenuItem = mfi;
}
else
{
var subItem = new MenuFlyoutSubItem() { Text = $"New {newItemType} menu item #{newItemLocalValue}" };
newMenuItem = subItem;
subItem.Add(mfi);
}

if (index == -1)
parent.Add(newMenuItem);
else
parent.Insert(index, newMenuItem);

newMenuItemCount++;
}
}
Expand Down
Expand Up @@ -9,6 +9,19 @@ protected override MenuFlyout CreatePlatformElement()
return new MenuFlyout();
}

protected override void DisconnectHandler(MenuFlyout platformView)
{
if (VirtualView is not null)
{
foreach (var item in VirtualView)
{
item.Handler?.DisconnectHandler();
}
}

base.DisconnectHandler(platformView);
}

public override void SetVirtualView(IElement view)
{
base.SetVirtualView(view);
Expand Down
Expand Up @@ -15,6 +15,14 @@ protected override MenuFlyoutSubItem CreatePlatformElement()

protected override void DisconnectHandler(MenuFlyoutSubItem PlatformView)
{
if (VirtualView is not null)
{
foreach (var item in VirtualView)
{
item.Handler?.DisconnectHandler();
}
}

base.DisconnectHandler(PlatformView);
PlatformView.Tapped -= OnTapped;
}
Expand Down Expand Up @@ -47,33 +55,66 @@ public static void MapSource(IMenuFlyoutSubItemHandler handler, IMenuFlyoutSubIt
public override void SetVirtualView(IElement view)
{
base.SetVirtualView(view);
Clear();
PlatformView.Items.Clear();

foreach (var item in ((IMenuFlyoutSubItem)view))
{
Add(item);
PlatformView.Items.Add((MenuFlyoutItemBase)item.ToPlatform(MauiContext!));
}
}

public void Add(IMenuElement view)
// workaround WinUI bug https://github.com/microsoft/microsoft-ui-xaml/issues/7797
void Reset()
{
PlatformView.Items.Add((MenuFlyoutItemBase)view.ToPlatform(MauiContext!));
}
if (VirtualView.Parent?.Handler is IElementHandler pvh)
{
var vv = VirtualView;
IList<MenuFlyoutItemBase>? items = null;
if (pvh.PlatformView is MenuFlyout mf)
{
items = mf.Items;

public void Remove(IMenuElement view)
{
if (view.Handler != null)
PlatformView.Items.Remove((MenuFlyoutItemBase)view.ToPlatform());
}
}
else if (pvh.PlatformView is MenuFlyoutSubItem mfsi)
{
items = mfsi.Items;
}

public void Clear()
{
PlatformView.Items.Clear();
}
if (items is not null)
{
var index = items.IndexOf(PlatformView);

public void Insert(int index, IMenuElement view)
{
PlatformView.Items.Insert(index, (MenuFlyoutItemBase)view.ToPlatform(MauiContext!));
if (index < 0)
return;

items.RemoveAt(index);

// You have to create the entire menu whenever adding/removing items.
// I tried to just remove and re-add this one item from the parent but that doesn't work.
// Also, if you try to reuse any MenuFlyoutItems on the new control it crashes.
//
// The following code crashes with a catastrophic failure.
//
// oldMenu.Items.Remove(item);
// newMenu.Items.Add(item);
// You have to create a new MenuFlyoutSubMenuItem and all of the children

vv.Handler?.DisconnectHandler();
items.Insert(index, (MenuFlyoutItemBase)vv.ToPlatform(MauiContext!));
}
}
}

public void Add(IMenuElement view) =>
Reset();

public void Remove(IMenuElement view) =>
Reset();

public void Clear() =>
Reset();

public void Insert(int index, IMenuElement view) =>
Reset();
}
}
Expand Up @@ -14,6 +14,7 @@ Microsoft.Maui.Layouts.FlexBasis.Equals(Microsoft.Maui.Layouts.FlexBasis other)
Microsoft.Maui.Platform.MauiWebView.MauiWebView(Microsoft.Maui.Handlers.WebViewHandler! handler) -> void
Microsoft.Maui.SizeRequest.Equals(Microsoft.Maui.SizeRequest other) -> bool
override Microsoft.Maui.Handlers.ContentViewHandler.DisconnectHandler(Microsoft.Maui.Platform.ContentPanel! platformView) -> void
override Microsoft.Maui.Handlers.MenuFlyoutHandler.DisconnectHandler(Microsoft.UI.Xaml.Controls.MenuFlyout! platformView) -> void
override Microsoft.Maui.Layouts.FlexBasis.Equals(object? obj) -> bool
override Microsoft.Maui.Layouts.FlexBasis.GetHashCode() -> int
override Microsoft.Maui.SizeRequest.Equals(object? obj) -> bool
Expand Down