MenuBar
See original GitHub issueDescription
Provide a cross platform API to allow the specification of a MenuBar for desktop applications.
Public API Changes
Option 1: Just Copy WinUI structures API
IMenuBarElement
This is used to attribute a view indicating that it has a MenuBar element that needs to be taken into consideration
public interface IMenuBarElement
{
IMenuBar? MenuBar { get; }
}
IMenuBar
Top Level container.
Alternative option here would be to use the existing Menu type.
public interface IMenuBar : IList<IMenuBarItem>, IElement
{
}
IMenuBarItem
Used to describe each primary menu inside the MenuBar
(File, edit, etc…)
public interface IMenuBarItem : IList<IMenuFlyoutItemBase>, IElement
{
string Text { get; }
MenuBarItemKey Key { get: }
}
MenuBarItemKey
Used to map a MenuBarItem to a system menu
public enum MenuBarItemKey
{
File, Edit, View, //The rest of the default menus in catalyst
}
IMenuFlyoutItem
Describes an item that the user will click on to trigger behavior
public interface IMenuFlyoutItem : IMenuFlyoutItemBase
{
string Text { get; }
Action Clicked { get; }
}
IMenuFlyoutSubItem
Used to create submenus
public interface IMenuFlyoutSubItem : IMenuFlyoutItemBase, IList<IMenuFlyoutItemBase>
{
string Text { get; }
short Position { get; } // ?? This can be used to insert sub menus at different points on catalyst
}
Platform Mappings
- WinUI : 1:1
- Catalyst
- MenuBar => UIMenuBuilder
- MenuBarItem => UIMenu
- MenuFlyoutItem => UIAction/UICommand
- MenuFlyoutSubItem => UIMenu
Considerations
We currently have a Menu API that is only used on MacOS. This API can be used as an attached property on every single Element. On MacOS this would become a context menu for Elements and the main menu when it was set on the Application. Do we want to keep this one type for both scenarios? On WinUI the FlyoutMenu's
all reuse the MenuFlyoutItem
types but then use MenuFlyout
as the parent element vs MenuBarItem
/MenuBar
Catalyst has a default menu that it displays, so the process of interacting with the menu is more modification based instead of just creating the menu like on WinUI. I’ve added a few APIs to help with this but we could do something more in v2. Just having the handlers will give users a valuable extension point to make modifications. They can just tap into the MenuBarHandler
and from there issue commands to the builder.
Intended Use-Case
https://developer.apple.com/documentation/uikit/uicommand/adding_menus_and_shortcuts_to_the_menu_bar_and_user_interface https://docs.microsoft.com/en-us/windows/winui/api/microsoft.ui.xaml.controls.menubar?view=winui-3.0
Issue Analytics
- State:
- Created 2 years ago
- Reactions:14
- Comments:6 (4 by maintainers)
I checked your implementation and it mostly fits my intuition (what is to say that I was able to grasp the structure right away), which I think is usually a good sign. That said, here are a few comments on the current design and naming.
My vote is for a unification of Menu/MenuBar and MenuItem/MenuFlyoutItem (and related items).
There are two aspect to this IMO.
a) You would probably want a context menu that can be added to other elements on WinUI as well. Right now (correct me if I’m wrong), MAUI only has context menu for ListView items. Not a general concept of context menu (for other views). In WinUI there is the ‘ContextFlyout’ property on ‘UIElement’ (https://docs.microsoft.com/de-de/uwp/api/windows.ui.xaml.uielement.contextflyout), which can be used to attach a context menu to any UIElement. So, I guess this is conceptionally similar to macOS.
b) We should have one unified way of building a window-/application-level menu in MAUI. Not a type that is specific to macOS.
I understand that with Catalyst you have a default menu. But I guess for a first iteration, you could “simply” merge the MAUI menu with the pre-existing default menu (by means of using the MenuBarItemKey flag and Position property, as you suggested in your API design, although the latter might need more thinking). At this point, it would probably require some custom logic to “apply” properties, commands, etc. to the existing menu items (e.g. in File menu).
I also think that the unified design should be based on your new proposal. The current/old Menu in MAUI has this (weird) structure with _menu and _items as two separate collections. So it’s used as a container (= MenuBar) and/or as a top-level menu (= MenuBarItem, e.g. File). For me this contradicts a self-documenting/explaining API design (and probably single-purpose rule). One potential reason is that its top-level menu was used (as item list) to populate the navigation menu for flyout pages (Hamburger menu).
MenuBar -> MenuBar is Ok
MenuBarItem -> Menu unless you build a window-/app-level menu(bar), this will be the root item/container for context menus or simple single-level menus (e.g. Hamburger menu). For that reason, MenuBar in its name is misleading as it can be used separate of MenuBar as well.
MenuFlyoutItem -> MenuItem MenuFlyoutSubItem -> MenuSubMenu(Item) Why do you have both? At least on Windows (WinForm, WPF, etc.) you can have a Click event for a submenu as well. So the only difference is that a submenu contains other menu items. Other than that it has all the same properties: text, icon, accelerator, (click) events. My guess is that having two separate types makes the handler mapping unique in MAUI, right? In that case, you could still make MenuFlyoutSubItem derive from MenuFlyoutItem, not?
Alright started wiring up the Catalyst parts and checked that all in. There’s some interesting parts we need to figure out with
Selectors
but otherwise it’s mostly working