A Docking Panels Library in .NET 2.0

Introduction

I've lost count of how many times I've seen on the C# forum the question "how do I write an application with the look and feel of Visual Studio?" The reply usually comes back that they should use a commercial library.

However, after looking at the examples that are available, I thought that it shouldn't be too difficult to write one personally; this is the result.

This assembly consists of two parts: the docking container part (in namespace Darwen.Windows.Forms.Controls.Docking) and the tabbed document control part (in namespace Darwen.Windows.Forms.Controls.TabbedDocuments). There's even a serializer static class (DockingControlsPersister) that saves and loads the docking state to a file in XML format.

I've also provided two example applications: one that creates and docks a large number of controls and another that is Notepad-like with docking panels.

Using the Library

The completed application for this walkthrough is provided as the "Tutorial" project.

I've going to assume that the reader has created a windows forms solution and added the docking controls libraries project. For details of how to do this see my previous article on MDI forms.

First, add a tool strip container menu strip, status strip, and tool strips to your application as required. Next, rebuild the project and then create an inherited user control by:

  1. Right-clicking your windows application project leaf in the solution explorer tree.
  2. Selecting 'add class' from the drop-down menu.
  3. Selecting 'inherited user control' from the list in the 'add new item' page.
  4. Typing the class name of your new control in the edit box below.
  5. Clicking 'add' and select 'DockingManagerControl' from the list.

Open your new user control in the forms designer and, on opening the toolbox, open the 'DockingControls' tab. Drag and drop the 'TabbedDocumentControl' onto your user control and set its dock style to 'Fill'.

Close your user control, rebuild your application, and then open your main form in the forms designer if it's not already open. Go to the toolbox and open the tab for your application. You will see your new control in the list. This should be dragged and dropped onto your main application; set its dock style to 'Fill'.

You've now done everything necessary to add the controls to your main form.

Layout

Controls are laid out in the following manner:

The DockingManagerControl is the top-level control, containing IDockingPanels (concrete class DockControlContainer) on the left, right, top, and bottom, which in turn contain IDockingControls (concrete class DockingControl) that contain the actual controls you specify.

First, you need to add a docking panel to contain the control you want to be dockable. Do this by calling the following inside of the constructor of your new user control (after the InitializeComponent call):

IDockingPanel rightPanel =
   this.Panels[DockingType.Right].InsertPanel(0);

Now that you have the panel to dock your control on, you can create a control (a textbox, for example) and dock it.

TextBox textBox   = new TextBox();
textBox.Name      = "Untitled";
textBox.Multiline = true;

IDockingControl dockingControl =
   rightPanel.DockedControls.Add("Text", textBox );

Well, that's pretty much all you need to do to create a docking control.

To have a form-looking docking control—in other words, one with multiple controls on it—create a user control containing the form's controls and then dock that. For an example, look at the 'find' docking control in the Notepad example.

To add a control to the tabbed document control, use the following:

TextBox textBox2   = new TextBox();
textBox2.Multiline = true;

// add the control and set its title
_tabbedDocumentControl.Items.Add("Title", textBox2);

where _tabbedDocumentControl is the member name of the TabbedDocumentControl you added to your new user control.

UI Class Details

I'll start with the bottom level classes, and move my way upwards.

IDockingControl (concrete class DockingControl)

This is created by the IDockingPanel.Items.Add call and is a control that wraps and dock-fills any control you specify. It contains methods to dock the control (DockControl), float the control (FloatControl), and change the state. Cancel could be otherwise called Closed, but this would conflict with the standard Close() meaning in Windows systems. In fact, when a control is cancelled it still exists, but is invisible. DockedDimension is the height of the control when docked with other controls to the left and right, and width when the control is docked to the top and the bottom.

IDockingPanel (concrete class DockControlContainer)

This is created by the DockingManagerControl.Panels.Add call. A docking panel contains docking controls. It exposes a collection of all the IDockingControls it contains along with whether it is tabbed.

It also has a Dimension property that is the width of the control when docked left or right and the height of the control when docked to the top or the bottom. The LayoutControls method is used when not in Tabbed mode, and auto-arranges all the docking controls so their heights are equal.

DockingManagerControl

The top level control. It has the Panels property that can be used to gain access to the inner docking panels. For instance, if you want to get the third panel from the left of the panels docked to the left, you use:

DockingManagerControl.Panels[DockingType.Left][2];

It also has a Renderer property that can be used to change the ToolStripRenderer used in the captions of the docking controls.

DockingControlsPersister

Contains serialization and deserialization methods to save and load the docking state of the DockingManagerControl.

Note: You should insert the call to Deserialize in either the OnLoad overridden method of your main form, after the call to base class, or in a handler for the Load event.

TabbedDocumentControl

Provides the tabbed document functionality. These are self explanatory (for example, SelectedControl property returns the currently selected control).

This control supports the usual keyboard shortcuts of:

  • Ctrl+Tab to move to the next document.
  • Ctrl+Shift+Tab to move to the previous document.
  • Ctrl+F4 to close the current document.

It also contains events for selection changed, a control being added, and a control being removed (or closed).

Useful Information

There are classes to encapsulate most behaviour that could be easily reused. For instance, the DragHandler class automates dragging and handles the escape keypress to cancel it.

One point of note is that MenuStrips and ToolStrips only work when the parent form is selected. This is somewhat annoying when having a floating window; it means you have to click twice on a button or menu item to get it to work as expected. The reason for this is that the WM_MOUSEACTIVATE message is eaten by the controls, not producing a corresponding MouseDown event. There are alternative implementations of ToolStrip and MenuStrip in the docking control library that fix the problem.

Conclusion

This library should be self explanatory and very easy to use. I recommend that anyone reading this article examine the implementation of the library because it does contain the solution to a number of interesting problems.

This library has been tested as much as it possible, but if anyone finds any bugs, I'll happily fix them and resubmit.



About the Author

David McClarnon

He first encountered Windows programming using Visual C++/MFC version 1.5 on Windows 3.11 a very long time ago. He is now a contract developer specialising in .NET/native interop with p/invoke.

Downloads

Comments

  • mr

    Posted by Peter on 01/15/2014 07:54pm

    Great David McClarnon thanks for this one thing how do i hide the close icon in a document Many thanks

    Reply
  • works with vb.net 2010?

    Posted by Roberto Guerrero on 05/11/2012 11:37pm

    excellent work. works with vb.net 2010?

    Reply
  • great work

    Posted by Ananthakumar Alwarsamy on 04/26/2012 12:08am

    It's great work . i was long time searching for this ... Thanks dude...rif

    Reply
  • Switching between usercontrols

    Posted by baychev on 01/09/2009 05:00am

    Darwen, Is it possible to switch from one user control to another by pressing a button on the former? I have a few controls in one of the panels and the panel is set to tabbed.

    Reply
  • memory leak

    Posted by ruskin.dantra on 04/11/2007 07:11pm

    Have you noticed a memory leak in your program, it occurs when you have a child form which inherits from the manager and contains a docking window, hide this window and then unhide it, none of the docking controls are removed?!
    
    Any help will be appreciated, you can email me on ruskin.dantra@gmail.com, thank you.

    Reply
  • Problem in using Mainform as a MDIParent

    Posted by nitin_vij on 12/12/2006 07:05am

    Hi there! Please take some time to read one issue I'll be really grateful.When I tried to use the MainForm used here as a MDI Form and open another window thru Menu the other form did not get opened. Could you pls guide me where I'm lacking. nitin_vij1981@yahoo.com Many Thanks Nitin

    • The MDIness...

      Posted by darwen on 12/12/2006 01:09pm

      ...is supposed to be taken care of by the TabbedDocument control. However if you want MDI a la old VC6 then you should be able to convert the DockingManagerControl to do it. Just make another class which is a copy of this control and change its inheritance to being from 'Form' instead of UserControl. You might have to do some mucking about but it shouldn't be difficult to take it further from this.

      Reply
    Reply
  • Great, but one problem

    Posted by Mad206 on 12/09/2006 08:43am

    Hi! I'm using two displays. When dragging a form I only see the "blue drag frame" on the right display. Any idea what's going wrong? Perhaps RectangleToScreen in class ControlRectangleDrag ?

    • Ah, dual displays....

      Posted by darwen on 12/12/2006 06:39am

      I think its to do with the DesktopGraphics stuff : its entirely possible that it will need to get the DC for whichever desktop is being addressed at that time. Unfortunately I don't have access to dual displays so have no way of fixing this.

      Reply
    Reply
  • Great Article

    Posted by HanneSThEGreaT on 12/04/2006 03:44am

    Very well done! Thanx

    • docking panel

      Posted by vjreddy2u on 07/26/2007 10:29am

      hi

      Reply
    Reply
  • Free Dock Panel Suite on Sourceforge

    Posted by jfcantin on 11/27/2006 04:40pm

    Darwen, Thanks for sharing your way of doing this. Most people that do not want to use a commercial version uses WeifenLuo's DockPanel Suite nowadays: http://sourceforge.net/projects/dockpanelsuite/ Best, JF

    • great!

      Posted by baygringo on 03/09/2007 09:45am

      Where can i get this class for old style mid support?

      Reply
    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Learn How A Global Entertainment Company Saw a 448% ROI Every business today uses software to manage systems, deliver products, and empower employees to do their jobs. But software inevitably breaks, and when it does, businesses lose money -- in the form of dissatisfied customers, missed SLAs or lost productivity. PagerDuty, an operations performance platform, solves this problem by helping operations engineers and developers more effectively manage and resolve incidents across a company's global operations. …

  • Today's agile organizations pose operations teams with a tremendous challenge: to deploy new releases to production immediately after development and testing is completed. To ensure that applications are deployed successfully, an automatic and transparent process is required. We refer to this process as Zero Touch Deployment™. This white paper reviews two approaches to Zero Touch Deployment--a script-based solution and a release automation platform. The article discusses how each can solve the key …

Most Popular Programming Stories

More for Developers

RSS Feeds