Click here to Skip to main content
11,583,859 members (63,704 online)
Click here to Skip to main content

WPF Docking Library

, 17 Jul 2007 CPOL 553.7K 16.7K 285
Rate this:
Please Sign up or sign in to vote.
A WPF library to easily integrate Windows docking features in applications like VS

Screenshot - ScrShot1.gif

Introduction

Recently, I started a project for porting a Windows Forms application to WPF. I was quite a novice in WPF, so at first I was considering using some type of Windows Forms interoperability. In particular, the WinForm application has cool docking functionalities that I wanted to port to a newer version. As I was going deeper into WPF technology, I discovered a new world that radically changed my initial ideas. In this article, I wish to share a library that implements the Windows docking feature in pure WPF without any Win32-interop.

Using the code

There are three fundamental classes: DockManager, DockableContent and DocumentContent. DockManager is a class responsible for managing the main window layout. Pane represents the window area that can be docked to a border. Each Pane contains one or more ManagedContent elements, which precisely refer to a window content element of the client code. Using this library is straightforward. DockManager is a user control that can be easily embedded into a window. For example, the following XAML code creates a DockManager in a DockPanel:

<Window x:Class="DockingDemo.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="DockingDemo" Height="500" Width="500"
    xmlns:custom="clr-namespace:DockingLibrary;assembly=DockingLibrary"
    Loaded="OnLoaded" Background="LightGray" >
    <DockPanel>
        <Menu DockPanel.Dock="Top">
                        <MenuItem Header="File">
                <MenuItem Header="New" Click="NewDocument"/>
                <MenuItem Header="Exit"  Click="ExitApplication"/>
            </MenuItem>
            <MenuItem Header="Edit"/>
            <MenuItem Header="Window">
                <MenuItem Header="Explorer" Click="ShowExplorerWindow"/>
                <MenuItem Header="Output"  Click="ShowOutputWindow"/>
                <MenuItem Header="Property" Click="ShowPropertyWindow"/>
                <MenuItem Header="ToDoList"  Click="ShowListWindow"/>
            </MenuItem>
            <MenuItem Header="?"/>
        </Menu>
        <ToolBar DockPanel.Dock="Top">
            <Button>OK</Button>
        </ToolBar>
        <custom:DockManager Name ="DockManager"/>
    </DockPanel>
</Window>

Notice that to use DockManager you have to refer an external CLR namespace, DockingLibary here. You can now add your windows to DockManager with code like this:

public partial class MainWindow : System.Windows.Window
{
    private TreeViewWindow explorerWindow = new TreeViewWindow();
    private OutputWindow outputWindow = new OutputWindow();
    private PropertyWindow propertyWindow = new PropertyWindow();
    private ListViewWindow listWindow = new ListViewWindow();

    public MainWindow()
    {
        InitializeComponent();
    }

    private void OnLoaded(object sender, EventArgs e)
    {
        //set window parent for dragging operations
        dockManager.ParentWindow = this;

        //Show PropertyWindow docked to the top border
        propertyWindow.DockManager = dockManager;
        propertyWindow.Show(Dock.Top);

        //Show ExplorerWindow docked to the right border as default
        explorerWindow.DockManager = dockManager;
        explorerWindow.Show();

        //Show ListWindow in documents pane
        listWindow.DockManager = dockManager;
        listWindow.ShowAsDocument();
    }
} 

Ib order to be dockable, a window must derive from DockableContent. Deriving from DockableContent indicates that the window content can be hosted in DockablePane. Windows are initially docked either where you set the Show member call or, by default, to the left border. The last thing to see is how to add a document window. A document window is a particular window that can't be docked to the main window border. It lives only in DocumentsPane which, as DockablePane, is a particular kind of Pane. The following code adds a document window with a unique title to DockManager:

private bool ContainsDocument(string docTitle)
{
    foreach (DockingLibrary.DocumentContent doc in DockManager.Documents)
    if (string.CompareOrdinal(doc.Title, docTitle) == 0)
    return true;
    return false;
}

private void NewDocument(object sender, EventArgs e)
{
    string title = "Document";
    int i = 1;
    while (ContainsDocument(title + i.ToString()))
    i++;

    DocumentWindow doc = new DocumentWindow();
    doc.Title = title+i.ToString();
    DockManager.AddDocumentContent(doc);
}

Points of interest

Exactly how is docking realized? I implement a simple algorithm here to manage relations between windows that are docked. DockingGrid contains code to organize Pane in a logical tree. DockManager calls DockingGrid.ArrangeLayout in order to organize the window layout. You also use DockingGrid.ChangeDock when you need to dock a Pane to a main window border. The following image shows a logical tree of panes. Don't get confused with the WPF logical tree.

Screenshot - DockingLibTree.jpg

Each node is a group of either two Panes or a Pane and a child. To arrange the layout, DockingGrid creates a WPF grid for each group with two columns or two rows, depending on split orientation. I hope the image is self-explanatory. Anyway, feel free to ask for more details if you are interested.

From version 0.1, the library supports floating windows, as you can see in VS. A floating window is an instance of the FloatingWindow class. It' s a very particular window because it needs to "float" between two windows. One is the parent window, MainWindow in this case, which is usually the main application window. The other is a transparent window owned by FloatingWindow itself, which is shown during dragging operations.

Screenshot - ScrShot2.gif

As you can see in the previous image, FloatingWindow supports useful switching options through a context menu on the title bar. In WinForms, controlling a non-client window area means overriding WndProc and managing relevant messages like WM_NCMOUSEMOVE.

In WPF, we have no access to messages posted to a window. This is because everything is controlled by the WPF engine that draws window content, fires keyboard and mouse events and does a lot of other things. The only way I know of to intercept messages is to install HwndSourceHook with a delegate to our functions. The following code shows how to manage a WM_NCLBUTTONDOWN message:

protected void OnLoaded(object sender, EventArgs e)
{
    WindowInteropHelper helper = new WindowInteropHelper(this);
    _hwndSource = HwndSource.FromHwnd(helper.Handle);
    _hwndSource.AddHook(new HwndSourceHook(this.HookHandler));
}

private IntPtr HookHandler(
    IntPtr hwnd,
    int msg,
    IntPtr wParam,
    IntPtr lParam,
    ref bool handled
    )
{
    handled = false;

    switch(msg)
    {
        case WM_NCLBUTTONDOWN:
        if (HostedPane.State == PaneState.DockableWindow && 
            wParam.ToInt32() == HTCAPTION)
        {
            short x = (short)((lParam.ToInt32() & 0xFFFF));
            short y = (short)((lParam.ToInt32() >> 16));

            HostedPane.ReferencedPane.DockManager.Drag(
                this, new Point(x, y), new Point(x - Left, y - Top));

            handled = true;}
            break;
        }
    }
}

Although the delegate signature looks like a window procedure signature, it's not the same thing. You can, however, handle every message, even WM_PAINT.

History

  • 13/05/07 -- First preliminary release
  • 17/05/07 -- Update
  • 11/06/07 -- Version 0.1: Floating window, many improvements and bug fixes
  • 16/07/07 -- Version 0.1.1: Some annoying bug fixes

License

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

Share

About the Author

adospace.NET
Systems Engineer
Italy Italy
I bought my first computer in Nov 1991, 21th and I started programming with QBasic under MSDOS.
Today my main interest is developping application with .NET 3.5.
Visit YouDev.net for tutorials on AvalonDock, download WPF controls, samples and code.

You may also be interested in...

Comments and Discussions

 
GeneralDockableContent Size Pin
Derek Bartram11-Mar-08 8:25
memberDerek Bartram11-Mar-08 8:25 
GeneralThe image is too wide Pin
Derek Bartram8-Mar-08 3:25
memberDerek Bartram8-Mar-08 3:25 
GeneralRe: The image is too wide Pin
adospace.NET9-Mar-08 23:22
memberadospace.NET9-Mar-08 23:22 
GeneralRe: The image is too wide Pin
Derek Bartram10-Mar-08 0:48
memberDerek Bartram10-Mar-08 0:48 
QuestionSave layout and docking?? Pin
arbrunda25-Jan-08 2:09
memberarbrunda25-Jan-08 2:09 
GeneralRe: Save layout and docking?? Pin
Sreekar198125-Jan-08 2:28
memberSreekar198125-Jan-08 2:28 
GeneralRe: Save layout and docking?? Pin
adospace.NET27-Jan-08 21:32
memberadospace.NET27-Jan-08 21:32 
QuestionHow to find the active Window of the DockManager Pin
simon.roderus6-Nov-07 1:53
membersimon.roderus6-Nov-07 1:53 
AnswerRe: How to find the active Window of the DockManager Pin
adospace.NET6-Nov-07 6:14
memberadospace.NET6-Nov-07 6:14 
QuestionRe: How to find the active Window of the DockManager Pin
simon.roderus7-Nov-07 2:26
membersimon.roderus7-Nov-07 2:26 
QuestionDo you have a version that compiles in Beta 2? Pin
DaveKolb28-Oct-07 17:54
memberDaveKolb28-Oct-07 17:54 
GeneralRestrictions on use Pin
mwalsma17-Oct-07 10:17
membermwalsma17-Oct-07 10:17 
GeneralRe: Restrictions on use Pin
adospace.NET21-Oct-07 22:43
memberadospace.NET21-Oct-07 22:43 
QuestionRe: Restrictions on use Pin
TGT27-Feb-08 4:59
memberTGT27-Feb-08 4:59 
So to clarify, WPF Docking Library can be used in the same way that AvalonDock can be used?

Thanks,
TGT Smile | :)
QuestionHow can we use this library in Acropolis Pin
sachinhadoltikar16-Oct-07 19:47
membersachinhadoltikar16-Oct-07 19:47 
AnswerRe: How can we use this library in Acropolis Pin
adospace.NET16-Oct-07 23:10
memberadospace.NET16-Oct-07 23:10 
GeneralWindow not showing after closing Pin
RajeshKumarRV30-Aug-07 18:46
memberRajeshKumarRV30-Aug-07 18:46 
GeneralWindows Disapear Pin
MiddleTommy29-Aug-07 8:53
memberMiddleTommy29-Aug-07 8:53 
GeneralRe: Windows Disapear Pin
adospace.NET31-Aug-07 4:28
memberadospace.NET31-Aug-07 4:28 
GeneralRe: Windows Disapear Pin
Derek Bartram12-Apr-08 14:33
memberDerek Bartram12-Apr-08 14:33 
GeneralTitle updating Pin
lntramper22-Jul-07 21:04
memberlntramper22-Jul-07 21:04 
GeneralRe: Title updating Pin
adospace.NET23-Jul-07 4:48
memberadospace.NET23-Jul-07 4:48 
GeneralDocking a Floating Pane inside aother pane by default. Pin
mani8520-Jul-07 2:03
membermani8520-Jul-07 2:03 
GeneralRe: Docking a Floating Pane inside aother pane by default. Pin
adospace.NET20-Jul-07 2:18
memberadospace.NET20-Jul-07 2:18 
GeneralRe: Docking a Floating Pane inside aother pane by default. Pin
mani8522-Jul-07 21:20
membermani8522-Jul-07 21:20 
GeneralRe: Docking a Floating Pane inside aother pane by default. Pin
mani8524-Jul-07 20:34
membermani8524-Jul-07 20:34 
GeneralRe: Docking a Floating Pane inside aother pane by default. Pin
azamat1-Jun-08 4:39
memberazamat1-Jun-08 4:39 
GeneralWinforms controls is drawn on top of flyout autohidden windows. Pin
Martin Webrant19-Jul-07 2:45
memberMartin Webrant19-Jul-07 2:45 
GeneralRe: Winforms controls is drawn on top of flyout autohidden windows. Pin
adospace.NET10-Aug-07 0:37
memberadospace.NET10-Aug-07 0:37 
Generalframes hosting Pin
Zajda8211-Jul-07 22:50
memberZajda8211-Jul-07 22:50 
GeneralRe: frames hosting Pin
adospace.NET16-Jul-07 8:39
memberadospace.NET16-Jul-07 8:39 
NewsNew version (0.1.8) Pin
adospace.NET28-Jun-07 10:07
memberadospace.NET28-Jun-07 10:07 
QuestionRe: New version (0.1.8) Pin
purohitrohit7-Jul-07 4:07
memberpurohitrohit7-Jul-07 4:07 
AnswerRe: New version (0.1.8) Pin
adospace.NET8-Jul-07 5:16
memberadospace.NET8-Jul-07 5:16 
QuestionCan we use Systems.Windows.Controls.Page? Pin
darreny28-Jun-07 0:43
memberdarreny28-Jun-07 0:43 
AnswerRe: Can we use Systems.Windows.Controls.Page? Pin
adospace.NET28-Jun-07 10:02
memberadospace.NET28-Jun-07 10:02 
GeneralRe: Can we use Systems.Windows.Controls.Page? Pin
Zajda8211-Jul-07 21:59
memberZajda8211-Jul-07 21:59 
Questionabout dispose Pin
duckle18-Jun-07 5:24
memberduckle18-Jun-07 5:24 
AnswerRe: about dispose Pin
adospace.NET18-Jun-07 5:29
memberadospace.NET18-Jun-07 5:29 
QuestionExtremely well done....question on sub-zones tho Pin
kfarley21515-Jun-07 10:35
memberkfarley21515-Jun-07 10:35 
AnswerRe: Extremely well done....question on sub-zones tho [modified] Pin
adospace.NET16-Jun-07 8:28
memberadospace.NET16-Jun-07 8:28 
GeneralExcellent work Pin
LogicalGenetics11-Jun-07 6:58
memberLogicalGenetics11-Jun-07 6:58 
GeneralRe: Excellent work Pin
adospace.NET11-Jun-07 11:45
memberadospace.NET11-Jun-07 11:45 
GeneralRe: Excellent work Pin
LogicalGenetics11-Jun-07 22:47
memberLogicalGenetics11-Jun-07 22:47 
GeneralRe: Excellent work Pin
adospace.NET11-Jun-07 22:59
memberadospace.NET11-Jun-07 22:59 
GeneralRe: Excellent work Pin
LogicalGenetics13-Jun-07 1:35
memberLogicalGenetics13-Jun-07 1:35 
GeneralRe: Excellent work Pin
purohitrohit25-Jun-07 2:35
memberpurohitrohit25-Jun-07 2:35 
Generalmore on DocumentsPane, general panes and toolbars Pin
Miguel Gomes11-Jun-07 0:16
memberMiguel Gomes11-Jun-07 0:16 
GeneralRe: more on DocumentsPane, general panes and toolbars Pin
adospace.NET11-Jun-07 11:29
memberadospace.NET11-Jun-07 11:29 
Generalbug with dockable content in the DocumentsPane Pin
Miguel Gomes6-Jun-07 0:04
memberMiguel Gomes6-Jun-07 0:04 

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

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

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.150603.1 | Last Updated 17 Jul 2007
Article Copyright 2007 by adospace.NET
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid