Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
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 @@ -49,25 +49,15 @@ public FlyoutItemDataTemplateSelector()

protected override DataTemplate? OnSelectTemplate(object item, BindableObject container)
{
DataTemplate template = DefaultItemTemplate;

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

if (bo is IMenuItemController)
bp = Shell.MenuItemTemplateProperty;
else
bp = Shell.ItemTemplateProperty;
var dataTemplate = Shell.ResolveFlyoutItemTemplate(container as Shell, bo);

if (bindableObjectWithTemplate.IsSet(bp) || container.IsSet(bp))
{
DataTemplate? dataTemplate = (container as IShellController)?.GetFlyoutItemDataTemplate(bo);
template = dataTemplate.SelectDataTemplate(item, container);
}
if (dataTemplate is not null)
return dataTemplate.SelectDataTemplate(item, container);
}
return template;

return DefaultItemTemplate;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,13 @@ void OnDataContextChanged(Microsoft.UI.Xaml.FrameworkElement sender, Microsoft.U

var element = bo as Element;
_shell = element?.FindParentOfType<Shell>();
DataTemplate dataTemplate = (_shell as IShellController)?.GetFlyoutItemDataTemplate(bo);

// Resolve the application supplied template through the same public contract external backends use.
// A null result means the application did not supply one, so fall back to the default flyout item cell.
DataTemplate dataTemplate = null;

if (bo != null && _shell != null)
dataTemplate = Shell.ResolveFlyoutItemTemplate(_shell, bo) ?? BaseShellItem.CreateDefaultFlyoutItemCell(bo);
Comment on lines +70 to +75

if (bo != null)
bo.PropertyChanged += ShellElementPropertyChanged;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -319,3 +319,4 @@ 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.ResolveFlyoutItemTemplate(Microsoft.Maui.Controls.Shell? shell, Microsoft.Maui.Controls.BindableObject! flyoutItem) -> Microsoft.Maui.Controls.DataTemplate?
Original file line number Diff line number Diff line change
Expand Up @@ -239,3 +239,4 @@ 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.ResolveFlyoutItemTemplate(Microsoft.Maui.Controls.Shell? shell, Microsoft.Maui.Controls.BindableObject! flyoutItem) -> Microsoft.Maui.Controls.DataTemplate?
Original file line number Diff line number Diff line change
Expand Up @@ -231,3 +231,4 @@ 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.ResolveFlyoutItemTemplate(Microsoft.Maui.Controls.Shell? shell, Microsoft.Maui.Controls.BindableObject! flyoutItem) -> Microsoft.Maui.Controls.DataTemplate?
Original file line number Diff line number Diff line change
Expand Up @@ -223,3 +223,4 @@ 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.ResolveFlyoutItemTemplate(Microsoft.Maui.Controls.Shell? shell, Microsoft.Maui.Controls.BindableObject! flyoutItem) -> Microsoft.Maui.Controls.DataTemplate?
Original file line number Diff line number Diff line change
Expand Up @@ -274,3 +274,4 @@ 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.ResolveFlyoutItemTemplate(Microsoft.Maui.Controls.Shell? shell, Microsoft.Maui.Controls.BindableObject! flyoutItem) -> Microsoft.Maui.Controls.DataTemplate?
Original file line number Diff line number Diff line change
Expand Up @@ -218,3 +218,4 @@ 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.ResolveFlyoutItemTemplate(Microsoft.Maui.Controls.Shell? shell, Microsoft.Maui.Controls.BindableObject! flyoutItem) -> Microsoft.Maui.Controls.DataTemplate?
Original file line number Diff line number Diff line change
Expand Up @@ -209,3 +209,4 @@ 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.ResolveFlyoutItemTemplate(Microsoft.Maui.Controls.Shell? shell, Microsoft.Maui.Controls.BindableObject! flyoutItem) -> Microsoft.Maui.Controls.DataTemplate?
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.GetBindableObjectWithFlyoutItemTemplate(bo)) as IStyleSelectable;
UpdateFlyoutItemStyles(g, styleClassSource);

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


#nullable enable
/// <summary>
/// Resolves the application-defined flyout <see cref="DataTemplate"/> for a flyout item.
/// </summary>
/// <param name="shell">
/// The <see cref="Shell"/> that owns <paramref name="flyoutItem"/>. When <see langword="null"/>, the owning Shell is
/// resolved from <paramref name="flyoutItem"/>; if it cannot be resolved, only templates set on the item itself are considered.
/// </param>
/// <param name="flyoutItem">A flyout item produced by <see cref="IShellController.GenerateFlyoutGrouping"/>.</param>
/// <returns>
/// The application-defined <see cref="DataTemplate"/> for <paramref name="flyoutItem"/>, or <see langword="null"/> when the
/// application has not supplied one and the caller should use its own platform-native default flyout item presentation.
/// </returns>
/// <exception cref="ArgumentNullException"><paramref name="flyoutItem"/> is <see langword="null"/>.</exception>
/// <remarks>
/// <para>
/// This is the supported entry point for custom Shell backends. It applies the same precedence the built-in backends use:
/// a template set on the item wins over a template set on the Shell, <see cref="MenuItemTemplateProperty"/> is used for menu
/// items and <see cref="ItemTemplateProperty"/> for everything else, and the pair of objects that backs a menu item is
/// resolved internally so a template set on either one is found.
/// </para>
/// <para>
/// The returned value may be a <see cref="DataTemplateSelector"/>. Call
/// <see cref="Internals.DataTemplateExtensions.SelectDataTemplate(DataTemplate, object, BindableObject)"/> before creating
/// content. Bind the created content to <paramref name="flyoutItem"/>, which is what the built-in Android, iOS, and Windows
/// backends do.
/// </para>
/// </remarks>
/// <example>
/// <code><![CDATA[
/// View CreateFlyoutItemView(Shell shell, BindableObject flyoutItem)
/// {
/// var template = Shell.ResolveFlyoutItemTemplate(shell, flyoutItem);
///
/// if (template is null)
/// return CreatePlatformDefaultFlyoutItemView(flyoutItem);
///
/// var view = (View)template.SelectDataTemplate(flyoutItem, shell).CreateContent();
/// view.BindingContext = flyoutItem;
/// return view;
/// }
/// ]]></code>
/// </example>
public static DataTemplate? ResolveFlyoutItemTemplate(Shell? shell, BindableObject flyoutItem)
{
if (flyoutItem is null)
throw new ArgumentNullException(nameof(flyoutItem));

shell ??= (flyoutItem as Element)?.FindParentOfType<Shell>();

BindableProperty bp = flyoutItem is IMenuItemController ? MenuItemTemplateProperty : ItemTemplateProperty;

// An explicitly set template wins even when its value is null, which lets an application opt a single item
// out of a Shell level template. A null value is reported as "no template" so callers fall back safely.
BindableObject templateSource = GetBindableObjectWithFlyoutItemTemplate(flyoutItem);
Comment on lines +786 to +788

if (templateSource.IsSet(bp))
return templateSource.GetValue(bp) as DataTemplate;

if (shell is not null && shell.IsSet(bp))
return shell.GetValue(bp) as DataTemplate;

return null;
}

/// <summary>
/// Gets the object that carries the flyout template for <paramref name="bo"/>.
/// </summary>
/// <remarks>
/// A menu item in the flyout is backed by a pair of objects: the public <see cref="MenuItem"/> and the internal
/// <c>MenuShellItem</c> wrapper (or the item's parent for <c>ShellContent.MenuItems</c>). The template may be set on
/// either one, so this resolves whichever object actually holds it.
/// </remarks>
internal static BindableObject GetBindableObjectWithFlyoutItemTemplate(BindableObject bo)
{
if (bo is IMenuItemController)
Expand All @@ -743,24 +816,10 @@ internal static BindableObject GetBindableObjectWithFlyoutItemTemplate(BindableO

return bo;
}
#nullable disable

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

if (bindableObjectWithTemplate.IsSet(bp))
{
return (DataTemplate)bindableObjectWithTemplate.GetValue(bp);
}

if (IsSet(bp))
{
return (DataTemplate)GetValue(bp);
}

return BaseShellItem.CreateDefaultFlyoutItemCell(bo);
}
=> ResolveFlyoutItemTemplate(this, bo) ?? BaseShellItem.CreateDefaultFlyoutItemCell(bo);

event EventHandler IShellController.StructureChanged
{
Expand Down
Loading
Loading