Vixen
dd8b0a81
csharp
public sealed class MenuPresenter

A menu bar built from a model, a registry and a keymap, and rebuilt when any of them changes.

No guide page documents this yet — the page shows what the code says about itself.

Remarks

The menu is a view, and this is the projection. Doc 11's claim that "menus, toolbars, context menus and the command palette are all views over the command registry" is either this class or a lie — the alternative is four places that each know Save is called Save, which is how an editor ends up with a toolbar button that stays enabled after the menu item went grey.

⚠ Enablement is applied as the menu opens, not as it is built — and this class no longer applies it. A menu built at start-up and never touched again would show whatever was true then; opening is the last moment before the user reads it, and it is cheap, one predicate per visible line. What changed is who does it: every line is bound to its id through ButtonBase.Command, and Menu refreshes its bound items from its own OpenChanged. Same moment, same predicate, one implementation.

⚠ Which means the registry has to be answerable in the document. A bound id resolves through CommandRoute, whose last link is ApplicationCommandResponder — so a presenter built over a registry nothing installed would grey every line with nothing failing anywhere. The constructor and both Context overloads install it when the document has not already been told, which EditorShell does for itself.

⚠ A rebuild replaces the bar rather than editing it. MenuBar can be added to and not removed from, and its menus are children of the document root rather than of the bar — so a presenter that tried to edit in place would leak a menu overlay per rebuild, invisible and still listening for pointer events.

⚠ And the replacement is put back where the first one was. Adding a child appends it, and a rebuild is triggered by anything anybody registers — so a bar built into an empty shell and rebuilt once the workspace and the status bar are in it comes back underneath both of them. In a column that is a menu bar along the bottom of the window, arriving on whichever frame the application happened to add its last command.

⚠ A rebuild is owed at the frame, not at the registration. The registry raises one event per command and the bar is rebuilt whole, so answering each one where it arrived made a hundred registrations a hundred bars. See Invalidate, which is where the count and the reason are.

Fields and properties (2)

  • public MenuModel Model

    What is on the bar.

  • public MenuBar Bar

    The bar itself, which is replaced by every rebuild.

Methods (5)

  • public MenuPresenter(UiElement host, MenuModel model, CommandRegistry commands, KeyMap keys)

    Builds a menu bar into an element.

  • public void Dispose()

    Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.

  • public void Rebuild()

    Throws the bar away and builds it again from the model.

  • public static ContextMenu Context(UiDocument document, CommandRegistry commands, KeyMap keys, params ReadOnlySpan<string?> commandIds)

    Builds a context menu over a set of commands.

  • public static ContextMenu Context(UiDocument document, MenuGroup group, CommandRegistry commands, KeyMap keys)

    Builds a context menu from a described group, submenus and all.

Used by (10)

  • EditorApplicationVixen.Editor.App
  • EditorSessionVixen.Editor.Testing
  • EditorShellVixen.Editor.Ui
  • EditorShellTestsVixen.Editor.Ui.Tests
  • MenuBarTestsVixen.Editor.App.Tests
  • MenuTestsVixen.Editor.Ui.Tests
  • PluginContextVixen.Editor.Plugin
  • StringCatalogChainTestsVixen.Editor.App.Tests
  • ToolbarPresenterVixen.Editor.Ui
  • ToolbarSectionTestsVixen.Editor.Ui.Tests