Menu Factory
Several Actipro products include built-in contextual menus. These menus are primarily based on the native menu controls of the Avalonia platform, and some controls expose events where these menus can be customized and/or cancelled.
While this approach is effective, it can be burdensome to identify and respond to all the appropriate events just to customize a menu. This is especially true if the Avalonia native menu controls need to be replaced by alternate menus (like those used by an application's main menu) since end-users expect all menus in an application to be consistent.
Replacing the Default Menus
All Actipro products will create built-in contextual menus using the menu factory currently assigned to MenuFactory.Current. By default, this value is initialized to a factory object that creates Avalonia native menu controls. This default instance is always available from the MenuFactory.Default property.
To change the factory object used by Actipro controls, set the MenuFactory.Current property to an instance of any class that implements the IMenuFactory interface.
Integrating with Actipro Bars
Actipro offers a Bars product, so we have made it easy to configure all Actipro products to use our own product. To change from the Avalonia native menus to Bars Context Menus, simply set MenuFactory.Current to a new instance of BarsMenuFactory.
using ActiproSoftware.UI.Avalonia.Controls;
using ActiproSoftware.UI.Avalonia.Controls.Bars;
...
public partial class App : Application {
public override void Initialize() {
// Configure BarsMenuFactory before initializing UI controls
MenuFactory.Current = new BarsMenuFactory();
...
AvaloniaXamlLoader.Load(this);
}
...
}
Integrating with 3rd Party Controls
Any implementation of IMenuFactory requires the base control types to derive from the Avalonia native menu controls:
Avalonia.Controls.MenuFlyout- The base type of contextual menus.Avalonia.Controls.MenuItem- The base type of items within a menu.Avalonia.Controls.Separator- The base type of separators between menu items.
The easiest way to implement IMenuFactory is to derive from MenuFactory<T,U,V>, where each of the generic type arguments identify the type to be used for menus, menu items, and menu separators. As needed, override the CreateMenuCore, CreateMenuItemCore, and CreateMenuSeparatorCore methods to instantiate and configure each respective control, as needed.
Tip
If you have custom menu-based controls that derive from Avalonia native controls and no other customization is necessary, you can easily configure the menu factory to use the custom types simply by specifying those types as the type arguments for the built-in MenuFactory<T,U,V> class, for example:
MenuFactory.Current = new MenuFactory<CustomMenuType, CustomMenuItemType, CustomSeparatorType>();
Working with Icons
The built-in MenuFactory<T,U,V> class, and any class that derives from it, provides several options for working with icons.
By default, menu items can support the display of icons if one is available. To force menu items to display without icons, set MenuFactory<T,U,V>.AllowIcons to false.
Image Provider
An Image Provider can be used to automatically associate icons for menu items. When a menu item is created, the calling routine passes an instance of MenuFactoryMenuItemOptions that describe the required menu item. If the options do not specify an Iconor IconTemplate but do provide a Key, that key will be passed to an overload of ImageProvider.GetImageSource that looks up an image based on a key. If the ImageProvider returns an image for that key, it will be used for the menu item.
The MenuFactory<T,U,V>.ImageProvider property is used to configure which image provider is used. When null, the ImageProvider.Default instance will be used. This property is set to null by default.
To disable looking up icons through an image provider, set MenuFactory<T,U,V>.CanResolveIconsThroughImageProvider to false.
Command Keys
Built-in contextual menus will request a specific key to be associated with each menu item, and constants are declared which define these keys. When attempting to programatically identify a menu item, it is always recommended to compare it to one of the available constants since the actual values could change over time. The following classes are available for command key constants, with some being specific to their respective assemblies:
ActiproSoftware.Properties.Shared.CommandKeysActiproSoftware.Properties.Docking.CommandKeys
Identifying a Menu Item
The Key will be assigned to MenuItem.Name and the attached AutomationIdProperty.
When using BarsMenuFactory, the Key will also be assigned to BarMenuItem.Key.
Using Menu Factory
While the menu factory classes were created to help ensure developers could easily customize the default menus created by Actipro products, there is no reason they cannot be used by anyone wanting a centralized way to manage their contextual menus. The following demonstrates how the current menu factory could be used to create a show a simple context menu:
using ActiproSoftware.Properties.Shared;
...
var menuFactory = MenuFactory.Current;
var menu = menuFactory.CreateMenu();
menu.Items.Add(menuFactory.CreateMenuItem(new MenuFactoryMenuItemOptions() { Key = CommandKeys.Edit.Cut, Text = "Cu_t", Command = MyCommands.Cut } ));
menu.Items.Add(menuFactory.CreateMenuItem(new MenuFactoryMenuItemOptions() { Key = CommandKeys.Edit.Copy, Text = "_Copy", Command = MyCommands.Copy } ));
menu.Items.Add(menuFactory.CreateMenuItem(new MenuFactoryMenuItemOptions() { Key = CommandKeys.Edit.Paste, Text = "_Paste", Command = MyCommands.Paste } ));
menu.Items.Add(menuFactory.CreateMenuSeparator());
menu.Items.Add(menuFactory.CreateMenuItem(new MenuFactoryMenuItemOptions() { Key = CommandKeys.Edit.Delete, Text = "_Delete", Command = MyCommands.Delete } ));
menu.ShowAt(myControl);