Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,7 @@ public FlyoutItemDataTemplateSelector()

if (item != null && item is BindableObject bo)
{
BindableProperty? bp = null;
var bindableObjectWithTemplate = Shell.GetBindableObjectWithFlyoutItemTemplate(bo);

if (bo is IMenuItemController)
bp = Shell.MenuItemTemplateProperty;
else
bp = Shell.ItemTemplateProperty;

if (bindableObjectWithTemplate.IsSet(bp) || container.IsSet(bp))
if (Shell.IsFlyoutItemTemplateSet(container as Shell, bo))
{
DataTemplate? dataTemplate = (container as IShellController)?.GetFlyoutItemDataTemplate(bo);
template = dataTemplate.SelectDataTemplate(item, container);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -319,3 +319,6 @@ virtual Microsoft.Maui.Controls.Platform.Compatibility.ShellFlyoutTemplatedConte
~static readonly Microsoft.Maui.Controls.TabbedPage.BadgeColorProperty -> Microsoft.Maui.Controls.BindableProperty
~static readonly Microsoft.Maui.Controls.TabbedPage.BadgeTextColorProperty -> Microsoft.Maui.Controls.BindableProperty
~static readonly Microsoft.Maui.Controls.TabbedPage.BadgeTextProperty -> Microsoft.Maui.Controls.BindableProperty
~static Microsoft.Maui.Controls.Shell.GetFlyoutItemTemplateProperty(Microsoft.Maui.Controls.BindableObject flyoutItem) -> Microsoft.Maui.Controls.BindableProperty
~static Microsoft.Maui.Controls.Shell.GetFlyoutItemTemplateSource(Microsoft.Maui.Controls.BindableObject flyoutItem) -> Microsoft.Maui.Controls.BindableObject
~static Microsoft.Maui.Controls.Shell.IsFlyoutItemTemplateSet(Microsoft.Maui.Controls.Shell shell, Microsoft.Maui.Controls.BindableObject flyoutItem) -> bool
Original file line number Diff line number Diff line change
Expand Up @@ -239,3 +239,6 @@ virtual Microsoft.Maui.Controls.LongPressingEventArgs.GetPosition(Microsoft.Maui
~static readonly Microsoft.Maui.Controls.TabbedPage.BadgeColorProperty -> Microsoft.Maui.Controls.BindableProperty
~static readonly Microsoft.Maui.Controls.TabbedPage.BadgeTextColorProperty -> Microsoft.Maui.Controls.BindableProperty
~static readonly Microsoft.Maui.Controls.TabbedPage.BadgeTextProperty -> Microsoft.Maui.Controls.BindableProperty
~static Microsoft.Maui.Controls.Shell.GetFlyoutItemTemplateProperty(Microsoft.Maui.Controls.BindableObject flyoutItem) -> Microsoft.Maui.Controls.BindableProperty
~static Microsoft.Maui.Controls.Shell.GetFlyoutItemTemplateSource(Microsoft.Maui.Controls.BindableObject flyoutItem) -> Microsoft.Maui.Controls.BindableObject
~static Microsoft.Maui.Controls.Shell.IsFlyoutItemTemplateSet(Microsoft.Maui.Controls.Shell shell, Microsoft.Maui.Controls.BindableObject flyoutItem) -> bool
Original file line number Diff line number Diff line change
Expand Up @@ -231,3 +231,6 @@ virtual Microsoft.Maui.Controls.LongPressingEventArgs.GetPosition(Microsoft.Maui
~static readonly Microsoft.Maui.Controls.TabbedPage.BadgeColorProperty -> Microsoft.Maui.Controls.BindableProperty
~static readonly Microsoft.Maui.Controls.TabbedPage.BadgeTextColorProperty -> Microsoft.Maui.Controls.BindableProperty
~static readonly Microsoft.Maui.Controls.TabbedPage.BadgeTextProperty -> Microsoft.Maui.Controls.BindableProperty
~static Microsoft.Maui.Controls.Shell.GetFlyoutItemTemplateProperty(Microsoft.Maui.Controls.BindableObject flyoutItem) -> Microsoft.Maui.Controls.BindableProperty
~static Microsoft.Maui.Controls.Shell.GetFlyoutItemTemplateSource(Microsoft.Maui.Controls.BindableObject flyoutItem) -> Microsoft.Maui.Controls.BindableObject
~static Microsoft.Maui.Controls.Shell.IsFlyoutItemTemplateSet(Microsoft.Maui.Controls.Shell shell, Microsoft.Maui.Controls.BindableObject flyoutItem) -> bool
Original file line number Diff line number Diff line change
Expand Up @@ -223,3 +223,6 @@ Microsoft.Maui.Controls.Label.~Label() -> void
~static readonly Microsoft.Maui.Controls.TabbedPage.BadgeColorProperty -> Microsoft.Maui.Controls.BindableProperty
~static readonly Microsoft.Maui.Controls.TabbedPage.BadgeTextColorProperty -> Microsoft.Maui.Controls.BindableProperty
~static readonly Microsoft.Maui.Controls.TabbedPage.BadgeTextProperty -> Microsoft.Maui.Controls.BindableProperty
~static Microsoft.Maui.Controls.Shell.GetFlyoutItemTemplateProperty(Microsoft.Maui.Controls.BindableObject flyoutItem) -> Microsoft.Maui.Controls.BindableProperty
~static Microsoft.Maui.Controls.Shell.GetFlyoutItemTemplateSource(Microsoft.Maui.Controls.BindableObject flyoutItem) -> Microsoft.Maui.Controls.BindableObject
~static Microsoft.Maui.Controls.Shell.IsFlyoutItemTemplateSet(Microsoft.Maui.Controls.Shell shell, Microsoft.Maui.Controls.BindableObject flyoutItem) -> bool
Original file line number Diff line number Diff line change
Expand Up @@ -274,3 +274,6 @@ static Microsoft.Maui.Controls.Platform.FormattedStringExtensions.ToRunAndColors
~static readonly Microsoft.Maui.Controls.TabbedPage.BadgeColorProperty -> Microsoft.Maui.Controls.BindableProperty
~static readonly Microsoft.Maui.Controls.TabbedPage.BadgeTextColorProperty -> Microsoft.Maui.Controls.BindableProperty
~static readonly Microsoft.Maui.Controls.TabbedPage.BadgeTextProperty -> Microsoft.Maui.Controls.BindableProperty
~static Microsoft.Maui.Controls.Shell.GetFlyoutItemTemplateProperty(Microsoft.Maui.Controls.BindableObject flyoutItem) -> Microsoft.Maui.Controls.BindableProperty
~static Microsoft.Maui.Controls.Shell.GetFlyoutItemTemplateSource(Microsoft.Maui.Controls.BindableObject flyoutItem) -> Microsoft.Maui.Controls.BindableObject
~static Microsoft.Maui.Controls.Shell.IsFlyoutItemTemplateSet(Microsoft.Maui.Controls.Shell shell, Microsoft.Maui.Controls.BindableObject flyoutItem) -> bool
3 changes: 3 additions & 0 deletions src/Controls/src/Core/PublicAPI/net/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -218,3 +218,6 @@ Microsoft.Maui.Controls.Label.~Label() -> void
~static readonly Microsoft.Maui.Controls.TabbedPage.BadgeColorProperty -> Microsoft.Maui.Controls.BindableProperty
~static readonly Microsoft.Maui.Controls.TabbedPage.BadgeTextColorProperty -> Microsoft.Maui.Controls.BindableProperty
~static readonly Microsoft.Maui.Controls.TabbedPage.BadgeTextProperty -> Microsoft.Maui.Controls.BindableProperty
~static Microsoft.Maui.Controls.Shell.GetFlyoutItemTemplateProperty(Microsoft.Maui.Controls.BindableObject flyoutItem) -> Microsoft.Maui.Controls.BindableProperty
~static Microsoft.Maui.Controls.Shell.GetFlyoutItemTemplateSource(Microsoft.Maui.Controls.BindableObject flyoutItem) -> Microsoft.Maui.Controls.BindableObject
~static Microsoft.Maui.Controls.Shell.IsFlyoutItemTemplateSet(Microsoft.Maui.Controls.Shell shell, Microsoft.Maui.Controls.BindableObject flyoutItem) -> bool
Original file line number Diff line number Diff line change
Expand Up @@ -209,3 +209,6 @@ Microsoft.Maui.Controls.Label.~Label() -> void
~static readonly Microsoft.Maui.Controls.TabbedPage.BadgeColorProperty -> Microsoft.Maui.Controls.BindableProperty
~static readonly Microsoft.Maui.Controls.TabbedPage.BadgeTextColorProperty -> Microsoft.Maui.Controls.BindableProperty
~static readonly Microsoft.Maui.Controls.TabbedPage.BadgeTextProperty -> Microsoft.Maui.Controls.BindableProperty
~static Microsoft.Maui.Controls.Shell.GetFlyoutItemTemplateProperty(Microsoft.Maui.Controls.BindableObject flyoutItem) -> Microsoft.Maui.Controls.BindableProperty
~static Microsoft.Maui.Controls.Shell.GetFlyoutItemTemplateSource(Microsoft.Maui.Controls.BindableObject flyoutItem) -> Microsoft.Maui.Controls.BindableObject
~static Microsoft.Maui.Controls.Shell.IsFlyoutItemTemplateSet(Microsoft.Maui.Controls.Shell shell, Microsoft.Maui.Controls.BindableObject flyoutItem) -> bool
2 changes: 1 addition & 1 deletion src/Controls/src/Core/Shell/BaseShellItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,7 @@ internal static DataTemplate CreateDefaultFlyoutItemCell(BindableObject bo)
if (sender is Grid g)
{
var bo = g.BindingContext as BindableObject;
var styleClassSource = Shell.GetBindableObjectWithFlyoutItemTemplate(bo) as IStyleSelectable;
var styleClassSource = (bo is null ? null : Shell.GetFlyoutItemTemplateSource(bo)) as IStyleSelectable;
UpdateFlyoutItemStyles(g, styleClassSource);

// this means they haven't changed the BaseShellItemContext so we are
Expand Down
97 changes: 90 additions & 7 deletions src/Controls/src/Core/Shell/Shell.cs
Original file line number Diff line number Diff line change
Expand Up @@ -731,23 +731,106 @@ static void OnShellAppearanceValueChanged(BindableObject bindable, object oldVal
List<IFlyoutBehaviorObserver> _flyoutBehaviorObservers = new List<IFlyoutBehaviorObserver>();


internal static BindableObject GetBindableObjectWithFlyoutItemTemplate(BindableObject bo)
/// <summary>
/// Gets the <see cref="BindableProperty"/> that Shell uses to look up the flyout <see cref="DataTemplate"/>
/// for <paramref name="flyoutItem"/>.
/// </summary>
/// <param name="flyoutItem">A flyout item produced by <see cref="IShellController.GenerateFlyoutGrouping"/>.</param>
/// <returns>
/// <see cref="MenuItemTemplateProperty"/> for menu items, otherwise <see cref="ItemTemplateProperty"/>.
/// </returns>
/// <exception cref="ArgumentNullException"><paramref name="flyoutItem"/> is <see langword="null"/>.</exception>
public static BindableProperty GetFlyoutItemTemplateProperty(BindableObject flyoutItem)
{
if (flyoutItem is null)
throw new ArgumentNullException(nameof(flyoutItem));

return flyoutItem is IMenuItemController ? MenuItemTemplateProperty : ItemTemplateProperty;
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch on the original revision — that concern is resolved by the redesign in 37f4a9c, which restored the helper rather than removing it.

Shell.GetBindableObjectWithFlyoutItemTemplate still exists with the identical signature, just internal and now documented:

internal static BindableObject GetBindableObjectWithFlyoutItemTemplate(BindableObject bo)

So both shipped binary profiles still resolve it — verified against the artifacts that Microsoft.Maui.Controls.targets actually imports:

$ strings maui.aotprofile    | grep -c GetBindableObjectWithFlyoutItemTemplate
1
$ strings maui-sc.aotprofile | grep -c GetBindableObjectWithFlyoutItemTemplate
1

IShellController.GetFlyoutItemDataTemplate is also unchanged in signature, so its profile entry (maui.aotprofile.txt:2056, maui-sc.aotprofile.txt:2575) stays valid too.

Two notes for the record:

  1. The .txt files are human-readable dumps, not build inputs — Controls.Build.Tasks.csproj packs nuget\** with Exclude="nuget\**\*.aotprofile.txt", and Microsoft.Maui.Controls.targets imports the binary maui.aotprofile / maui-sc.aotprofile. Hand-editing the .txt would have no effect on profiled AOT.
  2. The new ResolveFlyoutItemTemplate is not in the profiles, which is expected: the profiles are regenerated from a recorded run via src/ProfiledAot, not maintained by hand. It's a small non-virtual static on a path that is already only hit while building flyout items.


/// <summary>
/// Gets the <see cref="BindableObject"/> that carries the flyout <see cref="DataTemplate"/> for
/// <paramref name="flyoutItem"/>.
/// </summary>
/// <param name="flyoutItem">A flyout item produced by <see cref="IShellController.GenerateFlyoutGrouping"/>.</param>
/// <returns>
/// The object whose <see cref="MenuItemTemplateProperty"/> or <see cref="ItemTemplateProperty"/> value should be
/// inspected. This is usually <paramref name="flyoutItem"/> itself, but menu items are backed by a pair of objects
/// and the template may be set on either one, so the object that actually holds the template is returned.
/// </returns>
/// <exception cref="ArgumentNullException"><paramref name="flyoutItem"/> is <see langword="null"/>.</exception>
/// <remarks>
/// Custom Shell backends should use this method (rather than <paramref name="flyoutItem"/> directly) when resolving
/// the template, the <c>StyleClass</c> source, or the binding context for a flyout item, so that menu items behave
/// the same way they do on the built-in platform backends.
/// </remarks>
public static BindableObject GetFlyoutItemTemplateSource(BindableObject flyoutItem)
{
if (bo is IMenuItemController)
if (flyoutItem is null)
throw new ArgumentNullException(nameof(flyoutItem));

if (flyoutItem is IMenuItemController)
{
if (bo is MenuItem mi && mi.Parent != null && mi.Parent.IsSet(MenuItemTemplateProperty))
if (flyoutItem is MenuItem mi && mi.Parent != null && mi.Parent.IsSet(MenuItemTemplateProperty))
return mi.Parent;
else if (bo is MenuShellItem msi && msi.MenuItem != null && msi.MenuItem.IsSet(MenuItemTemplateProperty))
else if (flyoutItem is MenuShellItem msi && msi.MenuItem != null && msi.MenuItem.IsSet(MenuItemTemplateProperty))
return msi.MenuItem;
}

return bo;
return flyoutItem;
}

/// <summary>
/// Gets a value indicating whether an application-defined flyout <see cref="DataTemplate"/> applies to
/// <paramref name="flyoutItem"/>.
/// </summary>
/// <param name="shell">The Shell that owns <paramref name="flyoutItem"/>, or <see langword="null"/> to only consider templates set on the item itself.</param>
/// <param name="flyoutItem">A flyout item produced by <see cref="IShellController.GenerateFlyoutGrouping"/>.</param>
/// <returns>
/// <see langword="true"/> when <see cref="IShellController.GetFlyoutItemDataTemplate(BindableObject)"/> returns an
/// application-defined template; <see langword="false"/> when it falls back to the default flyout item template.
/// </returns>
/// <exception cref="ArgumentNullException"><paramref name="flyoutItem"/> is <see langword="null"/>.</exception>
/// <remarks>
/// Custom Shell backends call this to decide whether to use their own platform-specific default flyout item view
/// instead of the template returned by <see cref="IShellController.GetFlyoutItemDataTemplate(BindableObject)"/>.
/// </remarks>
/// <example>
/// <code><![CDATA[
/// DataTemplate SelectFlyoutItemTemplate(Shell shell, BindableObject flyoutItem)
/// {
/// if (!Shell.IsFlyoutItemTemplateSet(shell, flyoutItem))
/// return _platformDefaultTemplate;
///
/// return ((IShellController)shell).GetFlyoutItemDataTemplate(flyoutItem);
/// }
///
/// View CreateFlyoutItemView(Shell shell, BindableObject flyoutItem)
/// {
/// var template = SelectFlyoutItemTemplate(shell, flyoutItem);
/// var view = (View)template.SelectDataTemplate(flyoutItem, shell).CreateContent();
///
/// // Menu items are backed by a pair of objects, so the binding context has to come from the
/// // same object that supplied the template.
/// view.BindingContext = Shell.GetFlyoutItemTemplateSource(flyoutItem);
/// return view;
/// }
/// ]]></code>
/// </example>
public static bool IsFlyoutItemTemplateSet(Shell shell, BindableObject flyoutItem)
{
BindableProperty bp = GetFlyoutItemTemplateProperty(flyoutItem);

if (GetFlyoutItemTemplateSource(flyoutItem).IsSet(bp))
return true;

return shell is not null && shell.IsSet(bp);
}

DataTemplate IShellController.GetFlyoutItemDataTemplate(BindableObject bo)
{
BindableProperty bp = bo is IMenuItemController ? MenuItemTemplateProperty : ItemTemplateProperty;
var bindableObjectWithTemplate = GetBindableObjectWithFlyoutItemTemplate(bo);
BindableProperty bp = GetFlyoutItemTemplateProperty(bo);
var bindableObjectWithTemplate = GetFlyoutItemTemplateSource(bo);

if (bindableObjectWithTemplate.IsSet(bp))
{
Expand Down
Loading
Loading