2013/03/12

WPF: TextBox add item to default context menu

This post shows how you can inject MenuItems at the end of the TextBoxs default menu:

private Type _editorContextMenuType;
private MethodInfo _editorContextMenuAddMenuItemsMethod;
private Type _textBoxBaseType;
private FieldInfo _textBoxBaseTextEditorField;
private PropertyInfo _contextMenuEventArgsUserInitiatedProperty;

_editorContextMenuType = typeof(TextBox).Assembly.GetType("System.Windows.Documents.TextEditorContextMenu+EditorContextMenu");
_editorContextMenuAddMenuItemsMethod = _editorContextMenuType.GetMethod("AddMenuItems",
BindingFlags.NonPublic |
BindingFlags.Instance);
_textBoxBaseType = typeof(TextBoxBase);
_textBoxBaseTextEditorField = _textBoxBaseType
    .GetField("_textEditor", BindingFlags.NonPublic | BindingFlags.Instance);

_contextMenuEventArgsUserInitiatedProperty = typeof(ContextMenuEventArgs)
    .GetProperty("UserInitiated",
                  BindingFlags.NonPublic |
                  BindingFlags.Instance);

public static void InjectIntoDefaultMenu(this TextBoxBase textBoxBase, ContextMenuEventArgs e, Action callBaseContextMenuOpening, params MenuItem[] items)
{
    var contextMenu = (ContextMenu)Activator.CreateInstance(_editorContextMenuType, true);
    textBoxBase.ContextMenu = contextMenu;

    callBaseContextMenuOpening(e);

    _editorContextMenuAddMenuItemsMethod.Invoke(contextMenu, new[]
    {
        _textBoxBaseTextEditorField.GetValue(textBoxBase), 
        _contextMenuEventArgsUserInitiatedProperty.GetValue(e, null)
    });

    if (contextMenu.Items.Count > 0 && items.Length > 0)
        contextMenu.Items.Add(new Separator());

    foreach (var item in items)
        contextMenu.Items.Add(item);
}

Call this function on ContextMenuOpening of the TextBox like this:

this.InjectIntoDefaultMenu(e, p => base.OnContextMenuOpening(p), YOUMENUITEMS);

And you will see the default context menu incl. the spell checking menu if you use it and your menu item(s) at the end.


No comments:

Post a Comment