diff --git a/src/Compatibility/Core/src/Windows/CellControl.cs b/src/Compatibility/Core/src/Windows/CellControl.cs
index a0c6635c560d..3e8253f1628d 100644
--- a/src/Compatibility/Core/src/Windows/CellControl.cs
+++ b/src/Compatibility/Core/src/Windows/CellControl.cs
@@ -16,6 +16,8 @@
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Controls.Handlers.Compatibility;
using Microsoft.Maui.Controls.Platform;
+using WMenuFlyout = Microsoft.UI.Xaml.Controls.MenuFlyout;
+using WFlyoutBase = Microsoft.UI.Xaml.Controls.Primitives.FlyoutBase;
namespace Microsoft.Maui.Controls.Compatibility.Platform.UWP
{
@@ -284,9 +286,9 @@ void OnLongTap(object sender, HoldingRoutedEventArgs e)
///
/// To check the context, not just the text.
///
- MenuFlyout GetAttachedFlyout()
+ WMenuFlyout GetAttachedFlyout()
{
- if (FlyoutBase.GetAttachedFlyout(CellContent) is MenuFlyout flyout)
+ if (WFlyoutBase.GetAttachedFlyout(CellContent) is WMenuFlyout flyout)
{
var actions = Cell.ContextActions;
if (flyout.Items.Count != actions.Count)
@@ -306,16 +308,16 @@ void OpenContextMenu()
{
if (GetAttachedFlyout() == null)
{
- var flyout = new MenuFlyout();
+ var flyout = new WMenuFlyout();
SetupMenuItems(flyout);
((INotifyCollectionChanged)Cell.ContextActions).CollectionChanged += OnContextActionsChanged;
_contextActions = Cell.ContextActions;
- FlyoutBase.SetAttachedFlyout(CellContent, flyout);
+ WFlyoutBase.SetAttachedFlyout(CellContent, flyout);
}
- FlyoutBase.ShowAttachedFlyout(CellContent);
+ WFlyoutBase.ShowAttachedFlyout(CellContent);
}
void SetCell(object newContext)
@@ -441,7 +443,7 @@ void SetupContextMenu()
_contextActions = null;
}
- FlyoutBase.SetAttachedFlyout(CellContent, null);
+ WFlyoutBase.SetAttachedFlyout(CellContent, null);
return;
}
@@ -449,9 +451,9 @@ void SetupContextMenu()
CellContent.Holding += OnLongTap;
}
- void SetupMenuItems(MenuFlyout flyout)
+ void SetupMenuItems(WMenuFlyout flyout)
{
- foreach (MenuItem item in Cell.ContextActions)
+ foreach (var item in Cell.ContextActions)
{
var flyoutItem = new Microsoft.UI.Xaml.Controls.MenuFlyoutItem();
flyoutItem.SetBinding(UI.Xaml.Controls.MenuFlyoutItem.TextProperty, "Text");
diff --git a/src/Controls/samples/Controls.Sample.Sandbox/Maui.Controls.Sample.Sandbox.csproj b/src/Controls/samples/Controls.Sample.Sandbox/Maui.Controls.Sample.Sandbox.csproj
index 078cee17bcb8..89d2a6d7397b 100644
--- a/src/Controls/samples/Controls.Sample.Sandbox/Maui.Controls.Sample.Sandbox.csproj
+++ b/src/Controls/samples/Controls.Sample.Sandbox/Maui.Controls.Sample.Sandbox.csproj
@@ -8,8 +8,10 @@
- .NET MAUI Controls
- com.microsoft.maui.sample
+ .NET MAUI Controls Sandbox
+ com.microsoft.maui.sandbox
+ 5ee3361c-1cf9-443e-87f1-a7667fba9caa
+ 1.0
1
<_FastDeploymentDiagnosticLogging>True
diff --git a/src/Controls/samples/Controls.Sample.Sandbox/Platforms/Windows/Package.appxmanifest b/src/Controls/samples/Controls.Sample.Sandbox/Platforms/Windows/Package.appxmanifest
index 968c04010938..150bd01359db 100644
--- a/src/Controls/samples/Controls.Sample.Sandbox/Platforms/Windows/Package.appxmanifest
+++ b/src/Controls/samples/Controls.Sample.Sandbox/Platforms/Windows/Package.appxmanifest
@@ -6,10 +6,7 @@
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
IgnorableNamespaces="uap rescap">
-
+
$placeholder$
diff --git a/src/Controls/samples/Controls.Sample/Pages/Core/ContextFlyoutPage.xaml b/src/Controls/samples/Controls.Sample/Pages/Core/ContextFlyoutPage.xaml
new file mode 100644
index 000000000000..fcf700858c51
--- /dev/null
+++ b/src/Controls/samples/Controls.Sample/Pages/Core/ContextFlyoutPage.xaml
@@ -0,0 +1,128 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Controls/samples/Controls.Sample/Pages/Core/ContextFlyoutPage.xaml.cs b/src/Controls/samples/Controls.Sample/Pages/Core/ContextFlyoutPage.xaml.cs
new file mode 100644
index 000000000000..bb4d106da29e
--- /dev/null
+++ b/src/Controls/samples/Controls.Sample/Pages/Core/ContextFlyoutPage.xaml.cs
@@ -0,0 +1,121 @@
+using System;
+using System.Diagnostics;
+using System.Windows.Input;
+using Microsoft.Maui.Controls;
+using Microsoft.Maui.Graphics;
+
+namespace Maui.Controls.Sample.Pages
+{
+ public partial class ContextFlyoutPage
+ {
+ public ContextFlyoutPage()
+ {
+ InitializeComponent();
+
+ ImageContextCommand = new Command(
+ execute: async (object arg) =>
+ {
+ await DisplayAlert(
+ title: "Image",
+ message: $"The image's context menu was clicked via a command with parameter: {arg}",
+ cancel: "OK");
+ });
+
+ BindingContext = this;
+
+ ContextMenuWebView.HandlerChanged += OnWebViewHandlerChanged;
+ }
+
+
+ void OnWebViewHandlerChanged(object sender, EventArgs e)
+ {
+ if (ContextMenuWebView.Handler != null)
+ {
+#if WINDOWS
+ var webView2 = (Microsoft.UI.Xaml.Controls.WebView2)ContextMenuWebView.Handler.PlatformView;
+ webView2.CoreWebView2Initialized += OnWebView2CoreWebView2Initialized;
+#elif MACCATALYST
+ var wkWebView = (WebKit.WKWebView)ContextMenuWebView.Handler.PlatformView;
+ // TODO: Need to figure out how to disable default WKWebView context menu so that
+ // the custom context flyout is shown instead. (It does sometimes show up for a second
+ // but then it goes back to the default web context menu.)
+#endif
+ }
+ }
+
+#if WINDOWS
+ void OnWebView2CoreWebView2Initialized(Microsoft.UI.Xaml.Controls.WebView2 sender, Microsoft.UI.Xaml.Controls.CoreWebView2InitializedEventArgs args)
+ {
+ sender.CoreWebView2.Settings.AreDefaultContextMenusEnabled = false;
+ }
+#endif
+
+ public ICommand ImageContextCommand { get; init; }
+
+ int count;
+
+ void OnIncrementByOneClicked(object sender, EventArgs e)
+ {
+ count++;
+ OnPropertyChanged(nameof(CounterValue));
+ }
+
+ void OnIncrementMenuItemClicked(object sender, EventArgs e)
+ {
+ var menuItem = (MenuFlyoutItem)sender;
+ var incrementAmount = int.Parse((string)menuItem.CommandParameter);
+ count += incrementAmount;
+ OnPropertyChanged(nameof(CounterValue));
+ }
+
+ public string CounterValue => count.ToString("N0");
+
+ async void OnEntryShowTextClicked(object sender, EventArgs e)
+ {
+ await DisplayAlert(
+ title: "Entry",
+ message: $"The entry's text is: {EntryWithContextFlyout.Text}",
+ cancel: "OK");
+ }
+
+ void OnEntryAddTextClicked(object sender, EventArgs e)
+ {
+ EntryWithContextFlyout.Text += " more text!";
+ }
+
+ void OnEntryClearTextClicked(object sender, EventArgs e)
+ {
+ EntryWithContextFlyout.Text = "";
+ }
+
+ async void OnImageContextClicked(object sender, EventArgs e)
+ {
+ await DisplayAlert(
+ title: "Image",
+ message: $"The image's context menu was clicked",
+ cancel: "OK");
+ }
+
+ void OnWebViewGoToSiteClicked(object sender, EventArgs e)
+ {
+ ContextMenuWebView.Source = new UrlWebViewSource() { Url = "https://github.com/dotnet/maui", };
+ }
+
+ async void OnWebViewInvokeJSClicked(object sender, EventArgs e)
+ {
+ await ContextMenuWebView.EvaluateJavaScriptAsync(@"alert('help, i\'m being invoked!');");
+ }
+
+ void OnAddMenuClicked(object sender, EventArgs e)
+ {
+ var contextFlyout = ((MenuFlyoutItem)sender).Parent as MenuFlyout;
+ contextFlyout.Add(new MenuFlyoutItem() { Text = "Thank you for adding me" });
+ }
+
+ void OnSubMenuClicked(object sender, EventArgs e)
+ {
+ var subMenu = ((MenuFlyoutSubItem)sender);
+ subMenu.Add(new MenuFlyoutItem() { Text = "Thank you for adding me" });
+ }
+ }
+}
diff --git a/src/Controls/samples/Controls.Sample/ViewModels/CoreViewModel.cs b/src/Controls/samples/Controls.Sample/ViewModels/CoreViewModel.cs
index abcb55c1db22..b67c0942ad64 100644
--- a/src/Controls/samples/Controls.Sample/ViewModels/CoreViewModel.cs
+++ b/src/Controls/samples/Controls.Sample/ViewModels/CoreViewModel.cs
@@ -24,6 +24,9 @@ protected override IEnumerable CreateItems() => new[]
new SectionModel(typeof(ClipPage), "Clip",
"Defines the outline of the contents of an element."),
+ new SectionModel(typeof(ContextFlyoutPage), "ContextFlyout",
+ "Right-click context menu for controls."),
+
new SectionModel(typeof(ContentPageGallery), "ContentPage",
"Demonstrates using a Content Page."),
diff --git a/src/Controls/src/Core/BindableObject.cs b/src/Controls/src/Core/BindableObject.cs
index 94d4ba04dc01..e526e1f30260 100644
--- a/src/Controls/src/Core/BindableObject.cs
+++ b/src/Controls/src/Core/BindableObject.cs
@@ -272,6 +272,9 @@ protected virtual void OnBindingContextChanged()
if (Shell.GetTitleView(this) is View titleView)
SetInheritedBindingContext(titleView, BindingContext);
+
+ if (FlyoutBase.GetContextFlyout(this) is BindableObject contextFlyout)
+ SetInheritedBindingContext(contextFlyout, BindingContext);
}
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
diff --git a/src/Controls/src/Core/Compatibility/Handlers/ListView/Windows/CellControl.cs b/src/Controls/src/Core/Compatibility/Handlers/ListView/Windows/CellControl.cs
index 1dc0ece2f8e8..513a220da4a6 100644
--- a/src/Controls/src/Core/Compatibility/Handlers/ListView/Windows/CellControl.cs
+++ b/src/Controls/src/Core/Compatibility/Handlers/ListView/Windows/CellControl.cs
@@ -15,6 +15,8 @@
using WSolidColorBrush = Microsoft.UI.Xaml.Media.SolidColorBrush;
using Microsoft.Maui.Controls.Handlers.Compatibility;
using Windows.Foundation;
+using WMenuFlyout = Microsoft.UI.Xaml.Controls.MenuFlyout;
+using WFlyoutBase = Microsoft.UI.Xaml.Controls.Primitives.FlyoutBase;
namespace Microsoft.Maui.Controls.Platform.Compatibility
{
@@ -281,9 +283,9 @@ private void OnCellContentRightTapped(object sender, RightTappedRoutedEventArgs
///
/// To check the context, not just the text.
///
- MenuFlyout GetAttachedFlyout()
+ WMenuFlyout GetAttachedFlyout()
{
- if (FlyoutBase.GetAttachedFlyout(CellContent) is MenuFlyout flyout)
+ if (WFlyoutBase.GetAttachedFlyout(CellContent) is WMenuFlyout flyout)
{
var actions = Cell.ContextActions;
if (flyout.Items.Count != actions.Count)
@@ -303,16 +305,16 @@ void OpenContextMenu(Point point)
{
if (GetAttachedFlyout() == null)
{
- var flyout = new MenuFlyout();
+ var flyout = new WMenuFlyout();
SetupMenuItems(flyout);
((INotifyCollectionChanged)Cell.ContextActions).CollectionChanged += OnContextActionsChanged;
_contextActions = Cell.ContextActions;
- FlyoutBase.SetAttachedFlyout(CellContent, flyout);
+ WFlyoutBase.SetAttachedFlyout(CellContent, flyout);
}
- FlyoutBase
+ WFlyoutBase
.GetAttachedFlyout(CellContent)
.ShowAt(
CellContent,
@@ -444,14 +446,14 @@ void SetupContextMenu()
_contextActions = null;
}
- FlyoutBase.SetAttachedFlyout(CellContent, null);
+ WFlyoutBase.SetAttachedFlyout(CellContent, null);
return;
}
CellContent.RightTapped += OnCellContentRightTapped;
}
- void SetupMenuItems(MenuFlyout flyout)
+ void SetupMenuItems(WMenuFlyout flyout)
{
foreach (MenuItem item in Cell.ContextActions)
{
diff --git a/src/Controls/src/Core/ContextFlyout.cs b/src/Controls/src/Core/ContextFlyout.cs
new file mode 100644
index 000000000000..9a7e6e2c427c
--- /dev/null
+++ b/src/Controls/src/Core/ContextFlyout.cs
@@ -0,0 +1,120 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+
+namespace Microsoft.Maui.Controls
+{
+
+ public partial class MenuFlyout : FlyoutBase, IMenuFlyout // Same pattern as MenuBarItem
+ {
+ ReadOnlyCastingList _logicalChildren;
+ readonly ObservableCollection _menus = new ObservableCollection();
+
+ internal override IReadOnlyList LogicalChildrenInternal =>
+ _logicalChildren ??= new ReadOnlyCastingList(_menus);
+
+ public IMenuElement this[int index]
+ {
+ get { return _menus[index]; }
+ set
+ {
+ RemoveAt(index);
+ Insert(index, value);
+ }
+ }
+
+ public int Count => _menus.Count;
+
+ public bool IsReadOnly => false;
+
+ public void Add(IMenuElement item)
+ {
+ var index = _menus.Count;
+ _menus.Add(item);
+ NotifyHandler(nameof(IMenuFlyoutHandler.Add), index, item);
+
+ // Take care of the Element internal bookkeeping
+ if (item is Element element)
+ {
+ OnChildAdded(element);
+ }
+ }
+
+ public void Clear()
+ {
+ for (int i = _menus.Count - 1; i >= 0; i--)
+ RemoveAt(i);
+ }
+
+ public bool Contains(IMenuElement item)
+ {
+ return _menus.Contains(item);
+ }
+
+ public void CopyTo(IMenuElement[] array, int arrayIndex)
+ {
+ _menus.CopyTo(array, arrayIndex);
+ }
+
+ public IEnumerator GetEnumerator()
+ {
+ return _menus.GetEnumerator();
+ }
+
+ public int IndexOf(IMenuElement item)
+ {
+ return _menus.IndexOf(item);
+ }
+
+ public void Insert(int index, IMenuElement item)
+ {
+ _menus.Insert(index, item);
+ NotifyHandler(nameof(IMenuFlyoutHandler.Insert), index, item);
+
+ // Take care of the Element internal bookkeeping
+ if (item is Element element)
+ {
+ OnChildAdded(element);
+ }
+ }
+
+ public bool Remove(IMenuElement item)
+ {
+ var index = _menus.IndexOf(item);
+ var result = _menus.Remove(item);
+ NotifyHandler(nameof(IMenuFlyoutHandler.Remove), index, item);
+
+ // Take care of the Element internal bookkeeping
+ if (item is Element element)
+ {
+ OnChildRemoved(element, index);
+ }
+
+ return result;
+ }
+
+ public void RemoveAt(int index)
+ {
+ var item = _menus[index];
+ _menus.RemoveAt(index);
+ NotifyHandler(nameof(IMenuFlyoutHandler.Remove), index, item);
+
+ // Take care of the Element internal bookkeeping
+ if (item is Element element)
+ {
+ OnChildRemoved(element, index);
+ }
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return _menus.GetEnumerator();
+ }
+
+ void NotifyHandler(string action, int index, IMenuElement view)
+ {
+ Handler?.Invoke(action, new Maui.Handlers.ContextFlyoutItemHandlerUpdate(index, view));
+ }
+ }
+}
diff --git a/src/Controls/src/Core/FlyoutBase.cs b/src/Controls/src/Core/FlyoutBase.cs
new file mode 100644
index 000000000000..761ab4579721
--- /dev/null
+++ b/src/Controls/src/Core/FlyoutBase.cs
@@ -0,0 +1,26 @@
+namespace Microsoft.Maui.Controls
+{
+ public abstract class FlyoutBase : Element, IFlyout
+ {
+ public static readonly BindableProperty ContextFlyoutProperty = BindableProperty.CreateAttached("ContextFlyout", typeof(FlyoutBase), typeof(FlyoutBase), null,
+ propertyChanged: (bo, oldV, newV) =>
+ {
+ if (oldV is BindableObject oldMenu)
+ VisualElement.SetInheritedBindingContext(oldMenu, null);
+
+ if (newV is BindableObject newMenu)
+ VisualElement.SetInheritedBindingContext(newMenu, bo.BindingContext);
+
+ });
+
+ public static void SetContextFlyout(BindableObject b, FlyoutBase value)
+ {
+ b.SetValue(ContextFlyoutProperty, value);
+ }
+
+ public static FlyoutBase GetContextFlyout(BindableObject b)
+ {
+ return (FlyoutBase)b.GetValue(ContextFlyoutProperty);
+ }
+ }
+}
diff --git a/src/Controls/src/Core/HandlerImpl/Element/Element.Impl.cs b/src/Controls/src/Core/HandlerImpl/Element/Element.Impl.cs
index 65e3d48e6596..72543e3bca9e 100644
--- a/src/Controls/src/Core/HandlerImpl/Element/Element.Impl.cs
+++ b/src/Controls/src/Core/HandlerImpl/Element/Element.Impl.cs
@@ -5,7 +5,7 @@
namespace Microsoft.Maui.Controls
{
///
- public partial class Element : Maui.IElement, IEffectControlProvider, IToolTipElement
+ public partial class Element : Maui.IElement, IEffectControlProvider, IToolTipElement, IContextFlyoutElement
{
IElementHandler _handler;
EffectsFactory _effectsFactory;
@@ -100,5 +100,6 @@ void IEffectControlProvider.RegisterEffect(Effect effect)
}
ToolTip IToolTipElement.ToolTip => ToolTipProperties.GetToolTip(this);
+ IFlyout IContextFlyoutElement.ContextFlyout => FlyoutBase.GetContextFlyout(this);
}
}
diff --git a/src/Controls/src/Core/Layout/Layout.cs b/src/Controls/src/Core/Layout/Layout.cs
index 97c5876e7b5f..c88f0dbaf38a 100644
--- a/src/Controls/src/Core/Layout/Layout.cs
+++ b/src/Controls/src/Core/Layout/Layout.cs
@@ -261,8 +261,7 @@ protected virtual void OnUpdate(int index, IView view, IView oldView)
void NotifyHandler(string action, int index, IView view)
{
- var args = new Maui.Handlers.LayoutHandlerUpdate(index, view);
- Handler?.Invoke(action, args);
+ Handler?.Invoke(action, new Maui.Handlers.LayoutHandlerUpdate(index, view));
}
void IPaddingElement.OnPaddingPropertyChanged(Thickness oldValue, Thickness newValue)
diff --git a/src/Controls/src/Core/MenuBar.cs b/src/Controls/src/Core/MenuBar.cs
index 840a33417f72..c326e2cc0cf8 100644
--- a/src/Controls/src/Core/MenuBar.cs
+++ b/src/Controls/src/Core/MenuBar.cs
@@ -133,8 +133,7 @@ IEnumerator IEnumerable.GetEnumerator()
void NotifyHandler(string action, int index, IMenuBarItem view)
{
- var args = new Maui.Handlers.MenuBarHandlerUpdate(index, view);
- Handler?.Invoke(action, args);
+ Handler?.Invoke(action, new Maui.Handlers.MenuBarHandlerUpdate(index, view));
}
}
}
\ No newline at end of file
diff --git a/src/Controls/src/Core/MenuBarItem.cs b/src/Controls/src/Core/MenuBarItem.cs
index 999660bc7818..ab97f855a17f 100644
--- a/src/Controls/src/Core/MenuBarItem.cs
+++ b/src/Controls/src/Core/MenuBarItem.cs
@@ -140,8 +140,7 @@ IEnumerator IEnumerable.GetEnumerator()
void NotifyHandler(string action, int index, IMenuElement view)
{
- var args = new Maui.Handlers.MenuBarItemHandlerUpdate(index, view);
- Handler?.Invoke(action, args);
+ Handler?.Invoke(action, new Maui.Handlers.MenuBarItemHandlerUpdate(index, view));
}
}
}
\ No newline at end of file
diff --git a/src/Controls/src/Core/MenuFlyoutSubItem.cs b/src/Controls/src/Core/MenuFlyoutSubItem.cs
index 5ffe8a98b000..e8bda7696877 100644
--- a/src/Controls/src/Core/MenuFlyoutSubItem.cs
+++ b/src/Controls/src/Core/MenuFlyoutSubItem.cs
@@ -117,8 +117,7 @@ IEnumerator IEnumerable.GetEnumerator()
void NotifyHandler(string action, int index, IMenuElement view)
{
- var args = new Maui.Handlers.MenuFlyoutSubItemHandlerUpdate(index, view);
- Handler?.Invoke(action, args);
+ Handler?.Invoke(action, new Maui.Handlers.MenuFlyoutSubItemHandlerUpdate(index, view));
}
}
}
\ No newline at end of file
diff --git a/src/Controls/src/Core/PublicAPI/net-android/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/net-android/PublicAPI.Unshipped.txt
index a509317dc834..1127aa3bb1a9 100644
--- a/src/Controls/src/Core/PublicAPI/net-android/PublicAPI.Unshipped.txt
+++ b/src/Controls/src/Core/PublicAPI/net-android/PublicAPI.Unshipped.txt
@@ -1,4 +1,12 @@
#nullable enable
+Microsoft.Maui.Controls.FlyoutBase
+Microsoft.Maui.Controls.FlyoutBase.FlyoutBase() -> void
+Microsoft.Maui.Controls.MenuFlyout
+Microsoft.Maui.Controls.MenuFlyout.Clear() -> void
+Microsoft.Maui.Controls.MenuFlyout.MenuFlyout() -> void
+Microsoft.Maui.Controls.MenuFlyout.Count.get -> int
+Microsoft.Maui.Controls.MenuFlyout.IsReadOnly.get -> bool
+Microsoft.Maui.Controls.MenuFlyout.RemoveAt(int index) -> void
Microsoft.Maui.Controls.MenuFlyoutSeparator
Microsoft.Maui.Controls.MenuFlyoutSeparator.MenuFlyoutSeparator() -> void
Microsoft.Maui.Controls.ToolTipProperties
@@ -14,6 +22,15 @@ override Microsoft.Maui.Controls.TemplatedView.MeasureOverride(double widthConst
static Microsoft.Maui.Controls.ToolTipProperties.GetText(Microsoft.Maui.Controls.BindableObject! bindable) -> object!
static Microsoft.Maui.Controls.ToolTipProperties.SetText(Microsoft.Maui.Controls.BindableObject! bindable, object! value) -> void
static readonly Microsoft.Maui.Controls.ToolTipProperties.TextProperty -> Microsoft.Maui.Controls.BindableProperty!
+~Microsoft.Maui.Controls.MenuFlyout.Add(Microsoft.Maui.IMenuElement item) -> void
+~Microsoft.Maui.Controls.MenuFlyout.Contains(Microsoft.Maui.IMenuElement item) -> bool
+~Microsoft.Maui.Controls.MenuFlyout.CopyTo(Microsoft.Maui.IMenuElement[] array, int arrayIndex) -> void
+~Microsoft.Maui.Controls.MenuFlyout.GetEnumerator() -> System.Collections.Generic.IEnumerator
+~Microsoft.Maui.Controls.MenuFlyout.IndexOf(Microsoft.Maui.IMenuElement item) -> int
+~Microsoft.Maui.Controls.MenuFlyout.Insert(int index, Microsoft.Maui.IMenuElement item) -> void
+~Microsoft.Maui.Controls.MenuFlyout.Remove(Microsoft.Maui.IMenuElement item) -> bool
+~Microsoft.Maui.Controls.MenuFlyout.this[int index].get -> Microsoft.Maui.IMenuElement
+~Microsoft.Maui.Controls.MenuFlyout.this[int index].set -> void
~override Microsoft.Maui.Controls.Handlers.Compatibility.ViewCellRenderer.DisconnectHandler(Android.Views.View platformView) -> void
*REMOVED*override Microsoft.Maui.Controls.ContentView.ArrangeOverride(Microsoft.Maui.Graphics.Rect bounds) -> Microsoft.Maui.Graphics.Size
*REMOVED*override Microsoft.Maui.Controls.ContentView.MeasureOverride(double widthConstraint, double heightConstraint) -> Microsoft.Maui.Graphics.Size
@@ -22,3 +39,6 @@ static readonly Microsoft.Maui.Controls.ToolTipProperties.TextProperty -> Micros
*REMOVED*override Microsoft.Maui.Controls.FlexLayout.MeasureOverride(double widthConstraint, double heightConstraint) -> Microsoft.Maui.Graphics.Size
static readonly Microsoft.Maui.Controls.VisualElement.ZIndexProperty -> Microsoft.Maui.Controls.BindableProperty!
*REMOVED*override Microsoft.Maui.Controls.Platform.ControlsAccessibilityDelegate.OnInitializeAccessibilityNodeInfo(Android.Views.View? host, AndroidX.Core.View.Accessibility.AccessibilityNodeInfoCompat? info) -> void
+~static Microsoft.Maui.Controls.FlyoutBase.GetContextFlyout(Microsoft.Maui.Controls.BindableObject b) -> Microsoft.Maui.Controls.FlyoutBase
+~static Microsoft.Maui.Controls.FlyoutBase.SetContextFlyout(Microsoft.Maui.Controls.BindableObject b, Microsoft.Maui.Controls.FlyoutBase value) -> void
+~static readonly Microsoft.Maui.Controls.FlyoutBase.ContextFlyoutProperty -> Microsoft.Maui.Controls.BindableProperty
diff --git a/src/Controls/src/Core/PublicAPI/net-ios/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/net-ios/PublicAPI.Unshipped.txt
index 082757d294a7..e7b40843b15f 100644
--- a/src/Controls/src/Core/PublicAPI/net-ios/PublicAPI.Unshipped.txt
+++ b/src/Controls/src/Core/PublicAPI/net-ios/PublicAPI.Unshipped.txt
@@ -1,4 +1,12 @@
#nullable enable
+Microsoft.Maui.Controls.FlyoutBase
+Microsoft.Maui.Controls.FlyoutBase.FlyoutBase() -> void
+Microsoft.Maui.Controls.MenuFlyout
+Microsoft.Maui.Controls.MenuFlyout.Clear() -> void
+Microsoft.Maui.Controls.MenuFlyout.MenuFlyout() -> void
+Microsoft.Maui.Controls.MenuFlyout.Count.get -> int
+Microsoft.Maui.Controls.MenuFlyout.IsReadOnly.get -> bool
+Microsoft.Maui.Controls.MenuFlyout.RemoveAt(int index) -> void
Microsoft.Maui.Controls.MenuFlyoutSeparator
Microsoft.Maui.Controls.MenuFlyoutSeparator.MenuFlyoutSeparator() -> void
Microsoft.Maui.Controls.ToolTipProperties
@@ -19,3 +27,15 @@ static Microsoft.Maui.Controls.ToolTipProperties.GetText(Microsoft.Maui.Controls
static Microsoft.Maui.Controls.ToolTipProperties.SetText(Microsoft.Maui.Controls.BindableObject! bindable, object! value) -> void
static readonly Microsoft.Maui.Controls.ToolTipProperties.TextProperty -> Microsoft.Maui.Controls.BindableProperty!
static readonly Microsoft.Maui.Controls.VisualElement.ZIndexProperty -> Microsoft.Maui.Controls.BindableProperty!
+~Microsoft.Maui.Controls.MenuFlyout.Add(Microsoft.Maui.IMenuElement item) -> void
+~Microsoft.Maui.Controls.MenuFlyout.Contains(Microsoft.Maui.IMenuElement item) -> bool
+~Microsoft.Maui.Controls.MenuFlyout.CopyTo(Microsoft.Maui.IMenuElement[] array, int arrayIndex) -> void
+~Microsoft.Maui.Controls.MenuFlyout.GetEnumerator() -> System.Collections.Generic.IEnumerator
+~Microsoft.Maui.Controls.MenuFlyout.IndexOf(Microsoft.Maui.IMenuElement item) -> int
+~Microsoft.Maui.Controls.MenuFlyout.Insert(int index, Microsoft.Maui.IMenuElement item) -> void
+~Microsoft.Maui.Controls.MenuFlyout.Remove(Microsoft.Maui.IMenuElement item) -> bool
+~Microsoft.Maui.Controls.MenuFlyout.this[int index].get -> Microsoft.Maui.IMenuElement
+~Microsoft.Maui.Controls.MenuFlyout.this[int index].set -> void
+~static Microsoft.Maui.Controls.FlyoutBase.GetContextFlyout(Microsoft.Maui.Controls.BindableObject b) -> Microsoft.Maui.Controls.FlyoutBase
+~static Microsoft.Maui.Controls.FlyoutBase.SetContextFlyout(Microsoft.Maui.Controls.BindableObject b, Microsoft.Maui.Controls.FlyoutBase value) -> void
+~static readonly Microsoft.Maui.Controls.FlyoutBase.ContextFlyoutProperty -> Microsoft.Maui.Controls.BindableProperty
diff --git a/src/Controls/src/Core/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt
index 082757d294a7..e7b40843b15f 100644
--- a/src/Controls/src/Core/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt
+++ b/src/Controls/src/Core/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt
@@ -1,4 +1,12 @@
#nullable enable
+Microsoft.Maui.Controls.FlyoutBase
+Microsoft.Maui.Controls.FlyoutBase.FlyoutBase() -> void
+Microsoft.Maui.Controls.MenuFlyout
+Microsoft.Maui.Controls.MenuFlyout.Clear() -> void
+Microsoft.Maui.Controls.MenuFlyout.MenuFlyout() -> void
+Microsoft.Maui.Controls.MenuFlyout.Count.get -> int
+Microsoft.Maui.Controls.MenuFlyout.IsReadOnly.get -> bool
+Microsoft.Maui.Controls.MenuFlyout.RemoveAt(int index) -> void
Microsoft.Maui.Controls.MenuFlyoutSeparator
Microsoft.Maui.Controls.MenuFlyoutSeparator.MenuFlyoutSeparator() -> void
Microsoft.Maui.Controls.ToolTipProperties
@@ -19,3 +27,15 @@ static Microsoft.Maui.Controls.ToolTipProperties.GetText(Microsoft.Maui.Controls
static Microsoft.Maui.Controls.ToolTipProperties.SetText(Microsoft.Maui.Controls.BindableObject! bindable, object! value) -> void
static readonly Microsoft.Maui.Controls.ToolTipProperties.TextProperty -> Microsoft.Maui.Controls.BindableProperty!
static readonly Microsoft.Maui.Controls.VisualElement.ZIndexProperty -> Microsoft.Maui.Controls.BindableProperty!
+~Microsoft.Maui.Controls.MenuFlyout.Add(Microsoft.Maui.IMenuElement item) -> void
+~Microsoft.Maui.Controls.MenuFlyout.Contains(Microsoft.Maui.IMenuElement item) -> bool
+~Microsoft.Maui.Controls.MenuFlyout.CopyTo(Microsoft.Maui.IMenuElement[] array, int arrayIndex) -> void
+~Microsoft.Maui.Controls.MenuFlyout.GetEnumerator() -> System.Collections.Generic.IEnumerator
+~Microsoft.Maui.Controls.MenuFlyout.IndexOf(Microsoft.Maui.IMenuElement item) -> int
+~Microsoft.Maui.Controls.MenuFlyout.Insert(int index, Microsoft.Maui.IMenuElement item) -> void
+~Microsoft.Maui.Controls.MenuFlyout.Remove(Microsoft.Maui.IMenuElement item) -> bool
+~Microsoft.Maui.Controls.MenuFlyout.this[int index].get -> Microsoft.Maui.IMenuElement
+~Microsoft.Maui.Controls.MenuFlyout.this[int index].set -> void
+~static Microsoft.Maui.Controls.FlyoutBase.GetContextFlyout(Microsoft.Maui.Controls.BindableObject b) -> Microsoft.Maui.Controls.FlyoutBase
+~static Microsoft.Maui.Controls.FlyoutBase.SetContextFlyout(Microsoft.Maui.Controls.BindableObject b, Microsoft.Maui.Controls.FlyoutBase value) -> void
+~static readonly Microsoft.Maui.Controls.FlyoutBase.ContextFlyoutProperty -> Microsoft.Maui.Controls.BindableProperty
diff --git a/src/Controls/src/Core/PublicAPI/net-tizen/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/net-tizen/PublicAPI.Unshipped.txt
index 2a362b76050d..bf213f85eacb 100644
--- a/src/Controls/src/Core/PublicAPI/net-tizen/PublicAPI.Unshipped.txt
+++ b/src/Controls/src/Core/PublicAPI/net-tizen/PublicAPI.Unshipped.txt
@@ -1,4 +1,12 @@
#nullable enable
+Microsoft.Maui.Controls.FlyoutBase
+Microsoft.Maui.Controls.FlyoutBase.FlyoutBase() -> void
+Microsoft.Maui.Controls.MenuFlyout
+Microsoft.Maui.Controls.MenuFlyout.Clear() -> void
+Microsoft.Maui.Controls.MenuFlyout.MenuFlyout() -> void
+Microsoft.Maui.Controls.MenuFlyout.Count.get -> int
+Microsoft.Maui.Controls.MenuFlyout.IsReadOnly.get -> bool
+Microsoft.Maui.Controls.MenuFlyout.RemoveAt(int index) -> void
Microsoft.Maui.Controls.MenuFlyoutSeparator
Microsoft.Maui.Controls.MenuFlyoutSeparator.MenuFlyoutSeparator() -> void
Microsoft.Maui.Controls.ToolTipProperties
@@ -17,4 +25,16 @@ override Microsoft.Maui.Controls.TemplatedView.MeasureOverride(double widthConst
static Microsoft.Maui.Controls.ToolTipProperties.GetText(Microsoft.Maui.Controls.BindableObject! bindable) -> object!
static Microsoft.Maui.Controls.ToolTipProperties.SetText(Microsoft.Maui.Controls.BindableObject! bindable, object! value) -> void
static readonly Microsoft.Maui.Controls.ToolTipProperties.TextProperty -> Microsoft.Maui.Controls.BindableProperty!
-static readonly Microsoft.Maui.Controls.VisualElement.ZIndexProperty -> Microsoft.Maui.Controls.BindableProperty!
\ No newline at end of file
+static readonly Microsoft.Maui.Controls.VisualElement.ZIndexProperty -> Microsoft.Maui.Controls.BindableProperty!
+~Microsoft.Maui.Controls.MenuFlyout.Add(Microsoft.Maui.IMenuElement item) -> void
+~Microsoft.Maui.Controls.MenuFlyout.Contains(Microsoft.Maui.IMenuElement item) -> bool
+~Microsoft.Maui.Controls.MenuFlyout.CopyTo(Microsoft.Maui.IMenuElement[] array, int arrayIndex) -> void
+~Microsoft.Maui.Controls.MenuFlyout.GetEnumerator() -> System.Collections.Generic.IEnumerator
+~Microsoft.Maui.Controls.MenuFlyout.IndexOf(Microsoft.Maui.IMenuElement item) -> int
+~Microsoft.Maui.Controls.MenuFlyout.Insert(int index, Microsoft.Maui.IMenuElement item) -> void
+~Microsoft.Maui.Controls.MenuFlyout.Remove(Microsoft.Maui.IMenuElement item) -> bool
+~Microsoft.Maui.Controls.MenuFlyout.this[int index].get -> Microsoft.Maui.IMenuElement
+~Microsoft.Maui.Controls.MenuFlyout.this[int index].set -> void
+~static Microsoft.Maui.Controls.FlyoutBase.GetContextFlyout(Microsoft.Maui.Controls.BindableObject b) -> Microsoft.Maui.Controls.FlyoutBase
+~static Microsoft.Maui.Controls.FlyoutBase.SetContextFlyout(Microsoft.Maui.Controls.BindableObject b, Microsoft.Maui.Controls.FlyoutBase value) -> void
+~static readonly Microsoft.Maui.Controls.FlyoutBase.ContextFlyoutProperty -> Microsoft.Maui.Controls.BindableProperty
diff --git a/src/Controls/src/Core/PublicAPI/net-windows/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/net-windows/PublicAPI.Unshipped.txt
index 4724b14b146b..f30d626778e8 100644
--- a/src/Controls/src/Core/PublicAPI/net-windows/PublicAPI.Unshipped.txt
+++ b/src/Controls/src/Core/PublicAPI/net-windows/PublicAPI.Unshipped.txt
@@ -1,4 +1,12 @@
#nullable enable
+Microsoft.Maui.Controls.FlyoutBase
+Microsoft.Maui.Controls.FlyoutBase.FlyoutBase() -> void
+Microsoft.Maui.Controls.MenuFlyout
+Microsoft.Maui.Controls.MenuFlyout.Clear() -> void
+Microsoft.Maui.Controls.MenuFlyout.MenuFlyout() -> void
+Microsoft.Maui.Controls.MenuFlyout.Count.get -> int
+Microsoft.Maui.Controls.MenuFlyout.IsReadOnly.get -> bool
+Microsoft.Maui.Controls.MenuFlyout.RemoveAt(int index) -> void
Microsoft.Maui.Controls.Platform.ShellNavigationViewItem
Microsoft.Maui.Controls.Platform.ShellNavigationViewItem.ShellNavigationViewItem() -> void
Microsoft.Maui.Controls.Platform.ShellNavigationViewItemAutomationPeer
@@ -25,4 +33,16 @@ override Microsoft.Maui.Controls.TemplatedView.MeasureOverride(double widthConst
static readonly Microsoft.Maui.Controls.VisualElement.ZIndexProperty -> Microsoft.Maui.Controls.BindableProperty!
static Microsoft.Maui.Controls.ToolTipProperties.GetText(Microsoft.Maui.Controls.BindableObject! bindable) -> object!
static Microsoft.Maui.Controls.ToolTipProperties.SetText(Microsoft.Maui.Controls.BindableObject! bindable, object! value) -> void
-static readonly Microsoft.Maui.Controls.ToolTipProperties.TextProperty -> Microsoft.Maui.Controls.BindableProperty!
\ No newline at end of file
+static readonly Microsoft.Maui.Controls.ToolTipProperties.TextProperty -> Microsoft.Maui.Controls.BindableProperty!
+~Microsoft.Maui.Controls.MenuFlyout.Add(Microsoft.Maui.IMenuElement item) -> void
+~Microsoft.Maui.Controls.MenuFlyout.Contains(Microsoft.Maui.IMenuElement item) -> bool
+~Microsoft.Maui.Controls.MenuFlyout.CopyTo(Microsoft.Maui.IMenuElement[] array, int arrayIndex) -> void
+~Microsoft.Maui.Controls.MenuFlyout.GetEnumerator() -> System.Collections.Generic.IEnumerator
+~Microsoft.Maui.Controls.MenuFlyout.IndexOf(Microsoft.Maui.IMenuElement item) -> int
+~Microsoft.Maui.Controls.MenuFlyout.Insert(int index, Microsoft.Maui.IMenuElement item) -> void
+~Microsoft.Maui.Controls.MenuFlyout.Remove(Microsoft.Maui.IMenuElement item) -> bool
+~Microsoft.Maui.Controls.MenuFlyout.this[int index].get -> Microsoft.Maui.IMenuElement
+~Microsoft.Maui.Controls.MenuFlyout.this[int index].set -> void
+~static Microsoft.Maui.Controls.FlyoutBase.GetContextFlyout(Microsoft.Maui.Controls.BindableObject b) -> Microsoft.Maui.Controls.FlyoutBase
+~static Microsoft.Maui.Controls.FlyoutBase.SetContextFlyout(Microsoft.Maui.Controls.BindableObject b, Microsoft.Maui.Controls.FlyoutBase value) -> void
+~static readonly Microsoft.Maui.Controls.FlyoutBase.ContextFlyoutProperty -> Microsoft.Maui.Controls.BindableProperty
diff --git a/src/Controls/src/Core/PublicAPI/net/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/net/PublicAPI.Unshipped.txt
index 510c8e686fce..bf213f85eacb 100644
--- a/src/Controls/src/Core/PublicAPI/net/PublicAPI.Unshipped.txt
+++ b/src/Controls/src/Core/PublicAPI/net/PublicAPI.Unshipped.txt
@@ -1,4 +1,12 @@
#nullable enable
+Microsoft.Maui.Controls.FlyoutBase
+Microsoft.Maui.Controls.FlyoutBase.FlyoutBase() -> void
+Microsoft.Maui.Controls.MenuFlyout
+Microsoft.Maui.Controls.MenuFlyout.Clear() -> void
+Microsoft.Maui.Controls.MenuFlyout.MenuFlyout() -> void
+Microsoft.Maui.Controls.MenuFlyout.Count.get -> int
+Microsoft.Maui.Controls.MenuFlyout.IsReadOnly.get -> bool
+Microsoft.Maui.Controls.MenuFlyout.RemoveAt(int index) -> void
Microsoft.Maui.Controls.MenuFlyoutSeparator
Microsoft.Maui.Controls.MenuFlyoutSeparator.MenuFlyoutSeparator() -> void
Microsoft.Maui.Controls.ToolTipProperties
@@ -18,3 +26,15 @@ static Microsoft.Maui.Controls.ToolTipProperties.GetText(Microsoft.Maui.Controls
static Microsoft.Maui.Controls.ToolTipProperties.SetText(Microsoft.Maui.Controls.BindableObject! bindable, object! value) -> void
static readonly Microsoft.Maui.Controls.ToolTipProperties.TextProperty -> Microsoft.Maui.Controls.BindableProperty!
static readonly Microsoft.Maui.Controls.VisualElement.ZIndexProperty -> Microsoft.Maui.Controls.BindableProperty!
+~Microsoft.Maui.Controls.MenuFlyout.Add(Microsoft.Maui.IMenuElement item) -> void
+~Microsoft.Maui.Controls.MenuFlyout.Contains(Microsoft.Maui.IMenuElement item) -> bool
+~Microsoft.Maui.Controls.MenuFlyout.CopyTo(Microsoft.Maui.IMenuElement[] array, int arrayIndex) -> void
+~Microsoft.Maui.Controls.MenuFlyout.GetEnumerator() -> System.Collections.Generic.IEnumerator
+~Microsoft.Maui.Controls.MenuFlyout.IndexOf(Microsoft.Maui.IMenuElement item) -> int
+~Microsoft.Maui.Controls.MenuFlyout.Insert(int index, Microsoft.Maui.IMenuElement item) -> void
+~Microsoft.Maui.Controls.MenuFlyout.Remove(Microsoft.Maui.IMenuElement item) -> bool
+~Microsoft.Maui.Controls.MenuFlyout.this[int index].get -> Microsoft.Maui.IMenuElement
+~Microsoft.Maui.Controls.MenuFlyout.this[int index].set -> void
+~static Microsoft.Maui.Controls.FlyoutBase.GetContextFlyout(Microsoft.Maui.Controls.BindableObject b) -> Microsoft.Maui.Controls.FlyoutBase
+~static Microsoft.Maui.Controls.FlyoutBase.SetContextFlyout(Microsoft.Maui.Controls.BindableObject b, Microsoft.Maui.Controls.FlyoutBase value) -> void
+~static readonly Microsoft.Maui.Controls.FlyoutBase.ContextFlyoutProperty -> Microsoft.Maui.Controls.BindableProperty
diff --git a/src/Controls/src/Core/PublicAPI/netstandard/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/netstandard/PublicAPI.Unshipped.txt
index 2a362b76050d..bf213f85eacb 100644
--- a/src/Controls/src/Core/PublicAPI/netstandard/PublicAPI.Unshipped.txt
+++ b/src/Controls/src/Core/PublicAPI/netstandard/PublicAPI.Unshipped.txt
@@ -1,4 +1,12 @@
#nullable enable
+Microsoft.Maui.Controls.FlyoutBase
+Microsoft.Maui.Controls.FlyoutBase.FlyoutBase() -> void
+Microsoft.Maui.Controls.MenuFlyout
+Microsoft.Maui.Controls.MenuFlyout.Clear() -> void
+Microsoft.Maui.Controls.MenuFlyout.MenuFlyout() -> void
+Microsoft.Maui.Controls.MenuFlyout.Count.get -> int
+Microsoft.Maui.Controls.MenuFlyout.IsReadOnly.get -> bool
+Microsoft.Maui.Controls.MenuFlyout.RemoveAt(int index) -> void
Microsoft.Maui.Controls.MenuFlyoutSeparator
Microsoft.Maui.Controls.MenuFlyoutSeparator.MenuFlyoutSeparator() -> void
Microsoft.Maui.Controls.ToolTipProperties
@@ -17,4 +25,16 @@ override Microsoft.Maui.Controls.TemplatedView.MeasureOverride(double widthConst
static Microsoft.Maui.Controls.ToolTipProperties.GetText(Microsoft.Maui.Controls.BindableObject! bindable) -> object!
static Microsoft.Maui.Controls.ToolTipProperties.SetText(Microsoft.Maui.Controls.BindableObject! bindable, object! value) -> void
static readonly Microsoft.Maui.Controls.ToolTipProperties.TextProperty -> Microsoft.Maui.Controls.BindableProperty!
-static readonly Microsoft.Maui.Controls.VisualElement.ZIndexProperty -> Microsoft.Maui.Controls.BindableProperty!
\ No newline at end of file
+static readonly Microsoft.Maui.Controls.VisualElement.ZIndexProperty -> Microsoft.Maui.Controls.BindableProperty!
+~Microsoft.Maui.Controls.MenuFlyout.Add(Microsoft.Maui.IMenuElement item) -> void
+~Microsoft.Maui.Controls.MenuFlyout.Contains(Microsoft.Maui.IMenuElement item) -> bool
+~Microsoft.Maui.Controls.MenuFlyout.CopyTo(Microsoft.Maui.IMenuElement[] array, int arrayIndex) -> void
+~Microsoft.Maui.Controls.MenuFlyout.GetEnumerator() -> System.Collections.Generic.IEnumerator
+~Microsoft.Maui.Controls.MenuFlyout.IndexOf(Microsoft.Maui.IMenuElement item) -> int
+~Microsoft.Maui.Controls.MenuFlyout.Insert(int index, Microsoft.Maui.IMenuElement item) -> void
+~Microsoft.Maui.Controls.MenuFlyout.Remove(Microsoft.Maui.IMenuElement item) -> bool
+~Microsoft.Maui.Controls.MenuFlyout.this[int index].get -> Microsoft.Maui.IMenuElement
+~Microsoft.Maui.Controls.MenuFlyout.this[int index].set -> void
+~static Microsoft.Maui.Controls.FlyoutBase.GetContextFlyout(Microsoft.Maui.Controls.BindableObject b) -> Microsoft.Maui.Controls.FlyoutBase
+~static Microsoft.Maui.Controls.FlyoutBase.SetContextFlyout(Microsoft.Maui.Controls.BindableObject b, Microsoft.Maui.Controls.FlyoutBase value) -> void
+~static readonly Microsoft.Maui.Controls.FlyoutBase.ContextFlyoutProperty -> Microsoft.Maui.Controls.BindableProperty
diff --git a/src/Controls/src/Core/Shell/Shell.cs b/src/Controls/src/Core/Shell/Shell.cs
index 726e09275ac5..23dee2f67b72 100644
--- a/src/Controls/src/Core/Shell/Shell.cs
+++ b/src/Controls/src/Core/Shell/Shell.cs
@@ -619,6 +619,7 @@ bool IShellController.RemoveAppearanceObserver(IAppearanceObserver observer)
return true;
}
}
+
return false;
}
diff --git a/src/Controls/src/Core/View.cs b/src/Controls/src/Core/View.cs
index 831feb5e9f8d..394fbad678c2 100644
--- a/src/Controls/src/Core/View.cs
+++ b/src/Controls/src/Core/View.cs
@@ -3,6 +3,7 @@
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
+using Microsoft.Maui;
using Microsoft.Maui.Controls.Internals;
using Microsoft.Maui.Graphics;
diff --git a/src/Controls/src/Xaml/Hosting/AppHostBuilderExtensions.cs b/src/Controls/src/Xaml/Hosting/AppHostBuilderExtensions.cs
index e14c54f8fa6b..6e777343b916 100644
--- a/src/Controls/src/Xaml/Hosting/AppHostBuilderExtensions.cs
+++ b/src/Controls/src/Xaml/Hosting/AppHostBuilderExtensions.cs
@@ -109,6 +109,10 @@ public static IMauiHandlersCollection AddMauiControlsHandlers(this IMauiHandlers
handlersCollection.AddHandler(typeof(Frame), typeof(Handlers.Compatibility.FrameRenderer));
#endif
+#if WINDOWS || MACCATALYST
+ handlersCollection.AddHandler(typeof(MenuFlyout), typeof(MenuFlyoutHandler));
+#endif
+
#if IOS || MACCATALYST
handlersCollection.AddHandler(typeof(NavigationPage), typeof(Handlers.Compatibility.NavigationRenderer));
handlersCollection.AddHandler(typeof(TabbedPage), typeof(Handlers.Compatibility.TabbedRenderer));
@@ -136,7 +140,7 @@ public static IMauiHandlersCollection AddMauiControlsHandlers(this IMauiHandlers
handlersCollection.AddHandler();
handlersCollection.AddHandler();
#endif
- return handlersCollection;
+ return handlersCollection;
}
static MauiAppBuilder SetupDefaults(this MauiAppBuilder builder)
diff --git a/src/Controls/tests/Core.UnitTests/Menu/ContextFlyoutTests.cs b/src/Controls/tests/Core.UnitTests/Menu/ContextFlyoutTests.cs
new file mode 100644
index 000000000000..98a418c08675
--- /dev/null
+++ b/src/Controls/tests/Core.UnitTests/Menu/ContextFlyoutTests.cs
@@ -0,0 +1,106 @@
+#nullable enable
+using System;
+using System.Collections.Generic;
+using Microsoft.Maui.Handlers;
+using Xunit;
+
+namespace Microsoft.Maui.Controls.Core.UnitTests.Menu
+{
+ [Category("MenuFlyout")]
+ public class ContextFlyoutTests :
+ MenuTestBase
+ {
+ [Fact]
+ public void BindingContextPropagatesWhenContextFlyoutIsAlreadySetOnParent()
+ {
+ Button button = new Button();
+ var subMenuFlyout = new MenuFlyoutSubItem();
+ var menuFlyoutItem = new MenuFlyoutItem();
+ var menuFlyout = new MenuFlyout();
+ menuFlyout.Add(subMenuFlyout);
+ subMenuFlyout.Add(menuFlyoutItem);
+
+ FlyoutBase.SetContextFlyout(button, menuFlyout);
+
+ var bc = new Object();
+ button.BindingContext = bc;
+
+ Assert.Same(bc, subMenuFlyout.BindingContext);
+ Assert.Same(bc, menuFlyout.BindingContext);
+ }
+
+ [Fact]
+ public void BindingContextPropagatesWhenContextFlyoutIsSetAfterParentBindingContextIsSet()
+ {
+ Button button = new Button();
+ var subMenuFlyout = new MenuFlyoutSubItem();
+ var menuFlyoutItem = new MenuFlyoutItem();
+ subMenuFlyout.Add(menuFlyoutItem);
+
+ var bc = new Object();
+ button.BindingContext = bc;
+ var menuFlyout = new MenuFlyout();
+ menuFlyout.Add(subMenuFlyout);
+ FlyoutBase.SetContextFlyout(button, menuFlyout);
+
+ Assert.Same(bc, subMenuFlyout.BindingContext);
+ Assert.Same(bc, menuFlyout.BindingContext);
+ }
+
+ [Fact]
+ public void BindingContextPropagatesToAddedFlyoutItems()
+ {
+ Button button = new Button();
+ var subMenuFlyout = new MenuFlyoutSubItem();
+ var menuFlyoutItem = new MenuFlyoutItem();
+
+ var bc = new Object();
+ button.BindingContext = bc;
+ var menuFlyout = new MenuFlyout();
+ menuFlyout.Add(subMenuFlyout);
+ FlyoutBase.SetContextFlyout(button, menuFlyout);
+
+ // Add submenu after MenuFlyout is already set on Button
+ subMenuFlyout.Add(menuFlyoutItem);
+
+ Assert.Same(bc, subMenuFlyout.BindingContext);
+ Assert.Same(bc, menuFlyoutItem.BindingContext);
+ }
+
+ protected override int GetIndex(ContextFlyoutItemHandlerUpdate handlerUpdate)
+ => handlerUpdate.Index;
+
+ protected override IMenuElement GetItem(ContextFlyoutItemHandlerUpdate handlerUpdate) =>
+ handlerUpdate.MenuElement;
+
+ protected override void SetHandler(IElement element, List<(string Name, ContextFlyoutItemHandlerUpdate? Args)> events)
+ {
+ element.Handler = CreateMenuFlyoutHandler((n, h, l, a) => events.Add((n, a)));
+ }
+
+ MenuFlyoutHandler CreateMenuFlyoutHandler(Action? action)
+ {
+ var handler = new NonThrowingMenuFlyoutHandler(
+ MenuFlyoutHandler.Mapper,
+ new CommandMapper(MenuFlyoutHandler.CommandMapper)
+ {
+ [nameof(IMenuFlyoutHandler.Add)] = (h, l, a) => action?.Invoke(nameof(IMenuFlyoutHandler.Add), h, l, (ContextFlyoutItemHandlerUpdate?)a),
+ [nameof(IMenuFlyoutHandler.Remove)] = (h, l, a) => action?.Invoke(nameof(IMenuFlyoutHandler.Remove), h, l, (ContextFlyoutItemHandlerUpdate?)a),
+ [nameof(IMenuFlyoutHandler.Clear)] = (h, l, a) => action?.Invoke(nameof(IMenuFlyoutHandler.Clear), h, l, (ContextFlyoutItemHandlerUpdate?)a),
+ [nameof(IMenuFlyoutHandler.Insert)] = (h, l, a) => action?.Invoke(nameof(IMenuFlyoutHandler.Insert), h, l, (ContextFlyoutItemHandlerUpdate?)a),
+ });
+
+ return handler;
+ }
+
+ class NonThrowingMenuFlyoutHandler : MenuFlyoutHandler
+ {
+ public NonThrowingMenuFlyoutHandler(IPropertyMapper mapper, CommandMapper commandMapper)
+ : base(mapper, commandMapper)
+ {
+ }
+
+ protected override object CreatePlatformElement() => new object();
+ }
+ }
+}
diff --git a/src/Controls/tests/Core.UnitTests/Menu/MenuBarItemTests.cs b/src/Controls/tests/Core.UnitTests/Menu/MenuBarItemTests.cs
index 15cead251cb1..cbcc945ef394 100644
--- a/src/Controls/tests/Core.UnitTests/Menu/MenuBarItemTests.cs
+++ b/src/Controls/tests/Core.UnitTests/Menu/MenuBarItemTests.cs
@@ -8,7 +8,7 @@ namespace Microsoft.Maui.Controls.Core.UnitTests.Menu
{
[Category("MenuBarItem")]
public class MenuBarItemTests :
- MenuBarTestBase
+ MenuTestBase
{
protected override int GetIndex(MenuBarItemHandlerUpdate handlerUpdate) =>
handlerUpdate.Index;
diff --git a/src/Controls/tests/Core.UnitTests/Menu/MenuBarTests.cs b/src/Controls/tests/Core.UnitTests/Menu/MenuBarTests.cs
index 740fb65cf229..e9ed9f4a1859 100644
--- a/src/Controls/tests/Core.UnitTests/Menu/MenuBarTests.cs
+++ b/src/Controls/tests/Core.UnitTests/Menu/MenuBarTests.cs
@@ -8,7 +8,7 @@ namespace Microsoft.Maui.Controls.Core.UnitTests.Menu
{
[Category("MenuBar")]
public class MenuBarTests :
- MenuBarTestBase
+ MenuTestBase
{
protected override int GetIndex(MenuBarHandlerUpdate handlerUpdate) =>
handlerUpdate.Index;
diff --git a/src/Controls/tests/Core.UnitTests/Menu/MenuBarTrackerTests.cs b/src/Controls/tests/Core.UnitTests/Menu/MenuBarTrackerTests.cs
index 124e5472c1d5..27a618d85eff 100644
--- a/src/Controls/tests/Core.UnitTests/Menu/MenuBarTrackerTests.cs
+++ b/src/Controls/tests/Core.UnitTests/Menu/MenuBarTrackerTests.cs
@@ -5,7 +5,6 @@
namespace Microsoft.Maui.Controls.Core.UnitTests.MenuBarTests
{
-
public class MenuBarTrackerTests : BaseTestFixture
{
[Fact]
diff --git a/src/Controls/tests/Core.UnitTests/Menu/MenuFlyoutSubItemTests.cs b/src/Controls/tests/Core.UnitTests/Menu/MenuFlyoutSubItemTests.cs
index 4ca3287f7b51..6774eb4e7988 100644
--- a/src/Controls/tests/Core.UnitTests/Menu/MenuFlyoutSubItemTests.cs
+++ b/src/Controls/tests/Core.UnitTests/Menu/MenuFlyoutSubItemTests.cs
@@ -8,7 +8,7 @@ namespace Microsoft.Maui.Controls.Core.UnitTests.Menu
{
[Category("MenuFlyoutSubItem")]
public class MenuFlyoutSubItemTests :
- MenuBarTestBase
+ MenuTestBase
{
protected override int GetIndex(MenuFlyoutSubItemHandlerUpdate handlerUpdate) =>
handlerUpdate.Index;
diff --git a/src/Controls/tests/Core.UnitTests/Menu/MenuBarTestBase.cs b/src/Controls/tests/Core.UnitTests/Menu/MenuTestBase.cs
similarity index 96%
rename from src/Controls/tests/Core.UnitTests/Menu/MenuBarTestBase.cs
rename to src/Controls/tests/Core.UnitTests/Menu/MenuTestBase.cs
index 68acef96757b..da1452e45d89 100644
--- a/src/Controls/tests/Core.UnitTests/Menu/MenuBarTestBase.cs
+++ b/src/Controls/tests/Core.UnitTests/Menu/MenuTestBase.cs
@@ -5,7 +5,7 @@
namespace Microsoft.Maui.Controls.Core.UnitTests.Menu
{
- public abstract class MenuBarTestBase : BaseTestFixture
+ public abstract class MenuTestBase : BaseTestFixture
where TChildType : Element, TIChildType, new()
where TTestType : class, Maui.IElement, IList, new()
{
diff --git a/src/Controls/tests/DeviceTests/Elements/ContextFlyout/ContextFlyoutTests.Windows.cs b/src/Controls/tests/DeviceTests/Elements/ContextFlyout/ContextFlyoutTests.Windows.cs
new file mode 100644
index 000000000000..95b0927fc749
--- /dev/null
+++ b/src/Controls/tests/DeviceTests/Elements/ContextFlyout/ContextFlyoutTests.Windows.cs
@@ -0,0 +1,63 @@
+using System.Threading.Tasks;
+using Microsoft.Maui.Controls;
+using Microsoft.Maui.Platform;
+using Microsoft.Maui.Handlers;
+using Xunit;
+using System.Linq;
+using Microsoft.Maui.DeviceTests.Stubs;
+
+namespace Microsoft.Maui.DeviceTests
+{
+ public partial class ContextFlyoutTests : HandlerTestBase
+ {
+ [Fact(DisplayName = "Context flyout creates expected WinUI elements")]
+ public async Task ContextFlyoutCreatesExpectedWinUIElements()
+ {
+ SetupBuilder();
+ var toolbarItem = new ToolbarItem() { Text = "Toolbar Item 1" };
+ var firstPage = new ContentPage();
+
+ var window = new Window(firstPage);
+
+ await CreateHandlerAndAddToWindow(window, async (handler) =>
+ {
+ var labelWithContextFlyout = new Label();
+ var menu1 = new MenuFlyoutItem() { Text = "Menu1" };
+ var menu2 = new MenuFlyoutItem() { Text = "Menu2" };
+ var menu3 = new MenuFlyoutSeparator();
+
+ var menu4 = new MenuFlyoutSubItem() { Text = "Menu4" };
+ menu4.Add(new MenuFlyoutItem() { Text = "Menu4-a" });
+ menu4.Add(new MenuFlyoutItem() { Text = "Menu4-b" });
+
+ var menuFlyout = new MenuFlyout();
+ menuFlyout.Add(menu1);
+ menuFlyout.Add(menu2);
+ menuFlyout.Add(menu3);
+ menuFlyout.Add(menu4);
+
+ FlyoutBase.SetContextFlyout(labelWithContextFlyout, menuFlyout);
+
+ var contentPage = new ContentPage()
+ {
+ Content = labelWithContextFlyout,
+ };
+
+ window.Page = contentPage;
+
+ await OnLoadedAsync(contentPage);
+
+ var winLabel = ((LabelHandler)labelWithContextFlyout.Handler).PlatformView;
+ var contextFlyoutItems = ((Microsoft.UI.Xaml.Controls.MenuFlyout)winLabel.ContextFlyout).Items;
+ Assert.Equal(4, contextFlyoutItems.Count);
+ Assert.Equal("Menu1", ((Microsoft.UI.Xaml.Controls.MenuFlyoutItem)contextFlyoutItems[0]).Text);
+ Assert.Equal("Menu2", ((Microsoft.UI.Xaml.Controls.MenuFlyoutItem)contextFlyoutItems[1]).Text);
+ Assert.IsType(contextFlyoutItems[2]);
+ Assert.Equal("Menu4", ((Microsoft.UI.Xaml.Controls.MenuFlyoutSubItem)contextFlyoutItems[3]).Text);
+ Assert.Equal(2, ((Microsoft.UI.Xaml.Controls.MenuFlyoutSubItem)contextFlyoutItems[3]).Items.Count);
+ Assert.Equal("Menu4-a", ((Microsoft.UI.Xaml.Controls.MenuFlyoutItem)((Microsoft.UI.Xaml.Controls.MenuFlyoutSubItem)contextFlyoutItems[3]).Items[0]).Text);
+ Assert.Equal("Menu4-b", ((Microsoft.UI.Xaml.Controls.MenuFlyoutItem)((Microsoft.UI.Xaml.Controls.MenuFlyoutSubItem)contextFlyoutItems[3]).Items[1]).Text);
+ });
+ }
+ }
+}
diff --git a/src/Controls/tests/DeviceTests/Elements/ContextFlyout/ContextFlyoutTests.cs b/src/Controls/tests/DeviceTests/Elements/ContextFlyout/ContextFlyoutTests.cs
new file mode 100644
index 000000000000..899c2cf1c516
--- /dev/null
+++ b/src/Controls/tests/DeviceTests/Elements/ContextFlyout/ContextFlyoutTests.cs
@@ -0,0 +1,40 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.Maui;
+using Microsoft.Maui.Controls;
+using Microsoft.Maui.Controls.Handlers;
+using Microsoft.Maui.Platform;
+using Microsoft.Extensions.DependencyInjection;
+using Xunit;
+using Microsoft.Maui.Hosting;
+using Microsoft.Maui.Handlers;
+using Microsoft.Maui.Graphics;
+using Microsoft.Maui.DeviceTests.Stubs;
+
+namespace Microsoft.Maui.DeviceTests
+{
+
+ [Category(TestCategory.MenuFlyout)]
+ public partial class ContextFlyoutTests : HandlerTestBase
+ {
+ void SetupBuilder()
+ {
+ EnsureHandlerCreated(builder =>
+ {
+ builder.ConfigureMauiHandlers(handlers =>
+ {
+ handlers.AddHandler();
+ handlers.AddHandler