Click here to Skip to main content
15,867,686 members
Articles / Desktop Programming / Windows Forms
Tip/Trick

Tip: Minor Improvements on the DockPanel Suite, Part 1

Rate me:
Please Sign up or sign in to vote.
5.00/5 (3 votes)
6 Jul 2011CPOL2 min read 22.8K   2   1
This tip shows how to add support for New Horizontal Tab Group and New Vertical Tab Group commands to the Window menu of an application using the DockPanel Suite by Weifen Luo, and some other minor improvements to help decided if at least one of your windows is docked to the side of the main form an

Introduction


The DockPanel suite of UI tools, created by Weifen Luo, is a great open-source solution to making user interfaces that mimic the Visual Studio tabbed/docking windows environment.

I wanted to make a Window menu for the menu bar of my form that mimics that found in the Visual Studio environment. So I decided to derive off the main DockPanel class and call it StudioDockPanel and then put my minor improvements in this code.

One of the improvements is to implement the New Horizontal Tab Group and the New Vertical Tab Group commands that appear on the menu bar of the Visual Studio environment. These commands allow you to have one set of tabs "stacked" on top of another.

Code


To start off, first I derived a class, StudioDockPanel off of the DockPanel class provided by Weifen Luo:
C#
namespace MyProject
{
    public class StudioDockPanel : DockPanel
    {

    }
}
Next, I add an internal function, NewHorizontalTabGroup, to it:
C#
internal void NewHorizontalTabGroup()
{
    if (this.DocumentDockWindow == null
        || this.ActiveDocument == null)
        return; // just no-op on error

    IDockContent CurrentDocument = this.ActiveDocument;
    DockPane CurrentPane = this.ActiveContent.DockHandler.Pane;

    // create a new dock pane to the right of the current pane
    // and then transfer the document to the new pane
    DockPane NewPane = DockPaneFactory.CreateDockPane(CurrentDocument,
        CurrentPane, DockAlignment.Bottom, 0.5, true);
    NewPane.Show();
}
The DocumentDockWindow is a property I added in order to quickly find which of the DockPanel.DockWinodws is the one holding the tabbed document views:
C#
public DockWindow DocumentDockWindow
{
    get
    {
        foreach (DockWindow Window in DockWindows)
            if (Window.DockState == DockState.Document)
                return Window;
        return null;
    }
}
It's very straightforward; it just searches through the DockWindows list and returns the one whose DockState is set to DockState.Document. This is a public property, so you can drop this in your current code.

Moving along, now let's see how adding a new vertical tab group goes:
C#
internal void NewVerticalTabGroup()
{
    if (this.DocumentDockWindow == null
        || this.ActiveDocument == null)
        return; // just no-op on error

    IDockContent CurrentDocument = this.ActiveDocument;
    DockPane CurrentPane = this.ActiveContent.DockHandler.Pane;

    // create a new dock pane to the right of the current pane
    // and then transfer the document to the new pane
    DockPane NewPane = DockPaneFactory.CreateDockPane(CurrentDocument,
        CurrentPane, DockAlignment.Right, 0.5, true);
    NewPane.Show();
}
Now, when you have a Window menu, you want to update the UI of the menu commands themselves so they cannot be chosen unless there are more than 1 tabbed documents open. Otherwise, there is no content available to add to a new pane! For this purpose, i implemented a TwoOrMoreOpenDocumentWindows property:
C#
public bool TwoOrMoreOpenDocumentWindows
{
    get
    {
        if (this.DocumentDockWindow == null)
            return false;
        return this.DocumentDockWindow.VisibleNestedPanes[0].Contents.Count > 1;
    }
}
The IsDocumentVisible property tells you if there is an active document at all or not:
C#
public bool IsDocumentVisible
{
    get
    {
        return this.ActiveDocument != null;
    }
}
Finally, there is a requirement to know if there is at least one pane docked to the side of the window. This is to update the user interface and enable/disable the appropriate menu commands (Float, Dock, Dock as Tabbed Document, AutoHide, Hide etc.). So this helps us to put in a IsAtLeastOnePaneDocked property:
C#
public bool IsAtLeastOnePaneDocked
{
    get {
        foreach (DockWindow Window in DockWindows)
            if (Window.DockState != DockState.Document
                && Window.VisibleNestedPanes.Count > 0)
                return true;
        return false;
    }
}
And there we are. There are more updates and tips or tricks to come, as I make further enhancements to this library in order to bring it closer to UI standards for this type of environment.

Usage


To implement Window menu commands Float, Dock, Dock As Tabbed Document, AutoHide, and Hide, we do the following (the veriable names for the menu commands should be pretty self-explanatory):
C#
private void FloatWindow_Click(object sender, EventArgs e)
{
    if (this.MainDockPanel.ActiveContent == null)
        return;
    this.MainDockPanel.ActiveContent.DockHandler.DockState = DockState.Float;
}

private void DockWindow_Click(object sender, EventArgs e)
{
    if (this.MainDockPanel.ActiveContent == null)
        return;
    this.MainDockPanel.ActiveContent.DockHandler.DockTo(
        this.MainDockPanel, DockStyle.Left);
}

private void DockWindowAsTabbedDocument_Click(object sender, EventArgs e)
{
    if (this.MainDockPanel.ActiveContent == null)
        return;
    this.MainDockPanel.ActiveContent.DockHandler.DockState = DockState.Document;
}

private void AutoHideWindow_Click(object sender, EventArgs e)
{
    if (this.MainDockPanel.ActiveContent == null)
        return;
    switch (this.MainDockPanel.ActiveContent.DockHandler.DockState)
    {
        case DockState.DockLeft:
            this.MainDockPanel.ActiveContent.DockHandler.DockState = DockState.DockLeftAutoHide;
            break;
        case DockState.DockBottom:
            this.MainDockPanel.ActiveContent.DockHandler.DockState = DockState.DockBottomAutoHide;
            break;
        case DockState.DockRight:
            this.MainDockPanel.ActiveContent.DockHandler.DockState = DockState.DockRightAutoHide;
            break;
        case DockState.DockTop:
            this.MainDockPanel.ActiveContent.DockHandler.DockState = DockState.DockTopAutoHide;
            break;
        default:
            break;
    }
}

private void HideWindow_Click(object sender, EventArgs e)
{
    if (this.MainDockPanel.ActiveContent == null)
        return;
    this.MainDockPanel.ActiveContent.DockHandler.Hide();
}

private void AutoHideAll_Click(object sender, EventArgs e)
{
    foreach (DockContent content in this.MainDockPanel.Contents)
    {
        switch (content.DockState)
        {
            case DockState.DockLeft:
            case DockState.DockLeftAutoHide:
                content.DockState = DockState.DockLeftAutoHide;
                break;
            case DockState.DockBottom:
            case DockState.DockBottomAutoHide:
                content.DockState = DockState.DockBottomAutoHide;
                break;
            case DockState.DockRight:
            case DockState.DockRightAutoHide:
                content.DockState = DockState.DockRightAutoHide;
                break;
            case DockState.DockTop:
            case DockState.DockTopAutoHide:
                content.DockState = DockState.DockTopAutoHide;
                break;
            default:
                break;
        }
    }
}

private void NewHorizontalTabGroup_Click(object sender, EventArgs e)
{
    this.MainDockPanel.NewHorizontalTabGroup();
}

private void NewVerticalTabGroup_Click(object sender, EventArgs e)
{
    this.MainDockPanel.NewVerticalTabGroup();
}

private void ResetWindowLayout_Click(object sender, EventArgs e)
{
    // TODO: Add code here to reset the window layout to the default
    // Make sure to prompt the user to confirm
}
Finally, you'll want to update the Window menu commands appropriately:
C#
// This is a handler for the DropDownOpening event of the Window menu
private void UpdateWindowMenu(object sender, EventArgs e)
{
    int itemCount = windowMenu.DropDownItems.Count;
    if (windowMenu.DropDownItems[itemCount - 1] is ToolStripSeparator)
        windowMenu.DropDownItems.RemoveAt(itemCount - 1);
    this.CloseAllDocuments.Enabled =
        this.MdiChildren.Length > 0;
    this.AutoHideAll.Visible = this.MainDockPanel.IsAtLeastOnePaneDocked;
    this.NewHorizontalTabGroup.Visible = this.NewHorizontalTabGroup.Enabled = this.MainDockPanel.IsDocumentVisible
        && this.MainDockPanel.TwoOrMoreOpenDocumentWindows;
    this.NewVerticalTabGroup.Visible = this.NewVerticalTabGroup.Enabled = this.MainDockPanel.IsDocumentVisible
        && this.MainDockPanel.TwoOrMoreOpenDocumentWindows;
    if (this.MainDockPanel.ActiveContent == null)
    {
        this.FloatWindow.Enabled =
            this.DockWindow.Enabled =
            this.AutoHide.Enabled =
            this.DockWindowTabbedDocument.Enabled =
            this.HideWindow.Enabled = false;
        return;
    }
    switch (this.MainDockPanel.ActiveContent.DockHandler.DockState)
    {
        case DockState.Document:
        case DockState.Unknown:
            this.FloatWindow.Enabled = true;
            this.DockWindow.Enabled = true;
            this.DockWindowTabbedDocument.Enabled = false;
            this.AutoHide.Enabled = false;
            this.HideWindow.Enabled = false;
            break;
        case DockState.DockBottom:
        case DockState.DockBottomAutoHide:
        case DockState.DockLeft:
        case DockState.DockLeftAutoHide:
        case DockState.DockRight:
        case DockState.DockRightAutoHide:
        case DockState.DockTop:
        case DockState.DockTopAutoHide:
            this.FloatWindow.Enabled = true;
            this.DockWindow.Enabled = false;
            this.DockWindowTabbedDocument.Enabled = true;
            this.AutoHide.Enabled = true;
            this.HideWindow.Enabled = true;
            break;
        case DockState.Float:
            this.FloatWindow.Enabled = false;
            this.DockWindow.Enabled = true;
            this.DockWindowTabbedDocument.Enabled = true;
            this.AutoHide.Enabled = false;
            this.HideWindow.Enabled = true;
            break;
        default:
            break;
    }
}
And there you have it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Team Leader
United States United States
Brian C. Hart, Ph.D., is a strategic engagement leader on a mission to leverage space technology to protect U.S. interests and assets against adversaries. Throughout Dr. Hart's career, he has enjoyed: Working closely with business executives to provide strategic direction and leadership, translating customer and competitive intelligence into compelling capture strategies and solutions, and mentoring teams to enhance individual and company capabilities while fostering an engaging and accountable environment, being involved in STEAM initiatives and education to develop greater awareness in the community, and serving the armed forces with the U.S. Navy and U.S. Army National Guard. He is excited to begin developing his career in Jacobs's Critical Mission Systems business unit, supporting NORAD and the U.S. Space Force.

Comments and Discussions

 
Questionis there a way to embed DockPanel Suite into other components ? Pin
Prakash120625-Jun-16 18:33
Prakash120625-Jun-16 18:33 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.