Adding a menu item to a FlowDocumentReader ContextMenu

1.4k views Asked by At

The FlowDocumentReader has two menu items in its ContextMenu, Copy and Select All. I'd like to add an additional MenuItem to it and have tried this:

    private void FlowDocumentReader_ContextMenuOpening(object sender, ContextMenuEventArgs e)
    {
        flowDocumentReader.ContextMenu.Items.Clear();
        MenuItem menuItem = new MenuItem();
        menuItem.Header = "Test";
        flowDocumentReader.ContextMenu.Items.Add(menuItem);
    }

additionally I've tried this:

    private void FlowDocumentReader_ContextMenuOpening(object sender, ContextMenuEventArgs e)
    {
        MenuItem menuItem = new MenuItem();
        menuItem.Header = "Test";
        flowDocumentReader.ContextMenu.Items.Add(menuItem);
    }

where I don't clear the items in the context menu and attempt to append it. Neither of these work.

I can create my own menu like so:

    private void FlowDocumentReader_ContextMenuOpening(object sender, ContextMenuEventArgs e)
    {
        MenuItem menuItem = new MenuItem();
        menuItem.Header = "Test";
        flowDocumentReader.ContextMenu.Items.Add(menuItem);
        e.Handled = true;
        ContextMenu menu = new ContextMenu();
        MenuItem a = new MenuItem();
        a.Header = "A";
        menu.Items.Add(a);
        MenuItem b = new MenuItem();
        b.Header = "B";
        menu.Items.Add(b);
        flowDocumentReader.ContextMenu.Items.Clear();
        flowDocumentReader.ContextMenu = menu;
        menu.IsOpen = true;
    }

And that'll show up, but what I'd like to have is the Copy and Select All menu items as well as A and B.

Ideas?

2

There are 2 answers

0
itsmatt On BEST ANSWER

The solution I arrived at was to simply recreate those MenuItems on the new Menu and cancel the display of the built-in ContextMenu that is normally displayed. There are a number of built-in ApplicationCommands which can be incorporated into your own custom ContextMenu and the implementation of this is quite straightforward.

Assume that I've got a ContextMenu created from some method, GetContextMenu(), the following event handler rejects the opening of the built-in ContextMenu and substitutes the one returned from the call to GetContextMenu() and adds in the Copy command (Select All is similar).

private void flowDocumentReader_ContextMenuOpening(object sender, ContextMenuEventArgs e)
{
   e.Handled = true;  // keeps the built-in one from opening
   ContextMenu myMenu = GetContextMenu();
   MenuItem copyMenuItem = new MenuItem();
   copyMenuItem.Command = ApplicationCommand.Copy;
   copyMenuItem.CommandTarget = myFlowDocument;
   myMenu.Items.Add(copyMenuItem);
   ShowMenu(myMenu);
}

private void ShowMenu(ContextMenu menu)
{
   menu.Placement = PlacementMode.MousePoint;
   menu.PlacementRectangle = new Rect(0.0, 0.0, 0.0, 0.0);
   menu.IsOpen = true;
}
0
tvt173 On

You could also do this in the xaml for the FlowDocument:

<FlowDocument.ContextMenu>
     <ContextMenu>
          <MenuItem Header="{Resx Copy}" Command="Copy"/>
          <MenuItem Header="{Resx SelectAll}" Command="SelectAll"/>
          <MenuItem Header="{Resx CustomCommand}" Command="{Binding CustomCommand}"/>
     </ContextMenu>
</FlowDocument.ContextMenu>

(Headers conveniently localized thanks to Grant Frisken's Resx Extension) :)

If this needs to be applied to many FlowDocuments, you could also define it in a default style somewhere:

<Style TargetType="FlowDocument">
    <Setter Property="ContextMenu">
         <Setter.Value>
              <ContextMenu>
                  <MenuItem Header="{Resx Copy}" Command="Copy"/>
                  <MenuItem Header="{Resx SelectAll}" Command="SelectAll"/>
                  <MenuItem Header="{Resx CustomCommand}" Command="{Binding CustomCommand}"/>
              </ContextMenu>
         </Setter.Value>
    </Setter>
</Style>