0

When using DockPanelSuite, is it possible to have a context menu for the tab strip that is different from the one for a document tab? For example, right click an empty space on the tab strip and get one context menu then right click a document tab and get a different context menu specific to the document.

I tried setting the ContextMenuStrip property of the DockPanel. I got a context menu for any empty space on the DockPanel control as well as the document tab strip when visible and all open document tabs. That's a good start but I really only wanted the context menu for the tab strip. Not the main control or any tabs.

I also followed along with the sample project to make a context menu for the document by setting the TabPageContextMenuStrip property of the DockContent form. I discovered that you get a document specific context menu by right clicking the document tab, but it also overrides the DockPanel's ContextMenuStrip. While that is useful, it's still not the desired result.

Edit: Updating this post in case anyone else is interested in achieving the objective of the question. After much source code analysis and testing, I concluded that the objective could not be achieved using the available public Properties, Methods, and Events. However, we can achieve the goal by using a bit of reflection.

Discoveries:

DockContent.ContextMenuStrip

This property does nothing for the DockPanel. It will provide a context menu in the client area of the document. However, for some reason, the RichTextBox control set to Fill in the provided sample blocks the context menu from popping up.

DockContent.TabPageContextMenuStrip

This property causes the associated ContextMenuStrip to display when the document is active. However, it displays when you right click anywhere on the tab strip, not just when you right click the document tab.

Solution:

First, add a public property to the DockContent form which will contain a reference to the context menu.

public ContextMenuStrip TabContextMenu { get { return contextMenuTabPage; } }

Next, add an event handler in the MDI main form for the DockPanel.ActiveDocmentChanged event. This will be used to add an event handler to the tab strip after it’s been created.

this.dockPanel.ActiveDocumentChanged += new System.EventHandler(this.dockPanel_ActiveDocumentChanged);

private void dockPanel_ActiveDocumentChanged(object sender, EventArgs e)
{
  // Hook into the document pane tabstrip mouse up event
  // if we haven't already.
  if (dockPanel.ActiveDocumentPane != null
    && dockPanel.ActiveDocumentPane.TabStripControl != null
    && dockPanel.ActiveDocumentPane.TabStripControl.Tag == null)
  {
  dockPanel.ActiveDocumentPane.TabStripControl.Tag = "MouseUp Hooked";
  dockPanel.ActiveDocumentPane.TabStripControl.MouseUp +=
  TabStripControl_MouseUp;
  }
}

Finally, add the event handler for the TabStripControl.

private void TabStripControl_MouseUp(object sender, MouseEventArgs e)
{
  // Capture right click action
  if (e.Button == MouseButtons.Right)
  {
    ContextMenuStrip menu = contextMenuDocumentPane;
    Point screenPos = Cursor.Position;
    Point tabstripsPos = dockPanel.ActiveDocumentPane
      .TabStripControl.PointToClient(screenPos);

    // Determine if cursor is over a tab
    var tabstrip = dockPanel.ActiveDocumentPane.TabStripControl;
    var tabs = tabstrip.GetType()
      .GetProperty("Tabs", BindingFlags.Instance |
      BindingFlags.NonPublic).GetValue(tabstrip);
    foreach (var tab in (IEnumerable)tabs)
    {
      var bounds = tab.GetType()
        .GetProperty("Rectangle")
        .GetValue(tab);
      if (((Rectangle)bounds).Contains(tabstripsPos))
      {
        // Display context menu for this document tab
        var document = tab.GetType()
          .GetProperty("Content")
          .GetValue(tab);
        menu = ((ContentWindow)document).TabContextMenu;
      }
    }

    // Show appropriate context menu
    menu.Show(screenPos);
  }
}
Brad R.
  • 13
  • 5

0 Answers0