Click here to Skip to main content
Click here to Skip to main content

Building a Docking Window Management Solution in WPF

By , 1 Jan 2011
 

Introduction

Window docking is a familiar functionality in multi-windows applications. As a user interface developer, this behavior has always charmed me and so I thought of developing the same functionality in my own WPF toolkit. I know there are many implementations of similar solutions out there, some even open source, but my aim was to take this personal project as a challenge and learning opportunity.

I should also mention that the docking solution I have implemented is part of a bigger WPF toolkit that I am building on an ongoing basis under my company MixModes Inc, however I intend to keep it open source and royalty free project. To preview the full feature set of this library, you can visit my blog here.

Many existing implementations of window docking solutions have floating windows as separate windows managed under MDI parent window. However I have kept floating windows contained strictly within parent window as I intend to port this code to Silverlight soon.

I have also hosted this project on CodePlex at: http://mixmodessynergy.codeplex.com/.

Anatomy of Synergy Toolkit

MixModes Synergy toolkit consists of the following top level projects:

  • MixModes.Synergy.Resources – Contains image and language resources
  • MixModes.Synergy.Themes – Defines default themes for user controls, custom windows, colors, brushes and text themes
  • MixModes.Synergy.Utilities – Common utilities
  • MixModes.Synergy.VisualFramework – Contains behaviors, adorners, commands, user controls, docking framework and other WPF specific functionality
  • Synergy – Sample project highlighting features of the toolkit

Anatomy of Dockable Window

To understand window docking solution, it is necessary to understand the very primitive control that drives it all – the dockable window. A dockable window is a special window that in addition to content and title can be in the following several states:

  1. Pinned state – Dockable window can be pinned to the side of parent window to have consistent visibility. Usually frequently used content is pinned for easier and constant access.

    1.png

  2. Auto hidden state – Less frequently used windows can be auto hidden so when mouse is not hovering over them, they collapse into a condensed form (which I refer to as header). When mouse hovers over the headers, full window slides out from the docked side.

    2.png

  3. Document state – When used as a document, dockable windows can merge as tab items within a tab control.

    3.png

  4. Floating – Usual floating windows

    4.png

Docking window support is provided by DockPane control that is derivative of HeaderedContentControl. In addition to Header and Content properties that it inherits from HeaderedContentControl, it also contains the following properties:

  • Icon – Icon for the docked window
  • CondencedDockPanelTemplate – Template for condensed DockPane
  • CondencedDockPanel – Condensed form of DockPane
  • DockPaneState – State of the dock pane

DockPane also contains the following events:

  • Close – Close event
  • TogglePin – Toggling of pin / auto-hide button
  • HeaderDrag – Notification that user has started to drag header (title) of the DockPane

Default theme for DockPane is defined in the DockPane.xaml resource dictionary within MixModes.Synergy.Themes project.

Document Containers

DockPane(s) are contained within document containers. Document container is modelled via DocumentContainer class which is derivative of ContentControl. DocumentContainer can be in one of the following (mutually exclusive) states:

  • Empty DocumentContainer does not contain any DockPane
  • ContainsDocuments DocumentContainer contains one or more DockPane(s) as documents
  • SplitHorizontally DocumentContainer is split horizontally
  • SplitVertically - DocumentContainer is split vertically

5.png

DocumentContainer is complex in terms of its template since it is required to represent either a split view or a tabbed view. I have used a persistent TabControl within the template that is hidden if Content property is ever non-null. Content of-course is used exclusively to contain split views via Grid with two children DocumentContainer.

DocumentContainer contains the following properties:

  • State – State of the DocumentContainer
  • Documents – Contains documents represented in TabControl
  • DocumentsTab TabControl containing documents
  • DockIllustrationPanel – This is a panel which contains docking illustration points indicating to the user where a content should be docked. If user drags a DockPane to any one of these points, it gets docked at the respective position. The image below shows content of the DockIllustrationPanel:

6.png

DocumentContainer contains the following methods:

  • AddDockPane(DockPane, ContentDockPoint) – Adds a DockPane as a docked window
  • AddDocumentContainers(IEnumerable<DocumentContainer>, bool) – Splits and add child DocumentContainers
  • AddDocument(DockPane) – Adds a DockPane as a tabbed document
  • RemoveDocument(DockPane) – Removes a DockPane as a tabbed document

The template of DocumentContainer contains the following visuals in layers (bottom visuals are in increasing Z-Order):

  • TabControl (PART_DOCUMENTS) – Bound to Documents property of DocumentContainer
  • ContentPresenter – This is where split children are added
  • Grid (PART_DOCK_POINTS) – Panel for hosting dock illustration points
  • Grid (PART_DOCK_ILLUSTRATION) DockIllustrationPanel for illustrating future docking via cues

Windows Manager

Windows manager is the component that binds DockPanel(s) and DocumentContainer(s) together to provide window management functionality in applications. In addition, window manager contains auto-hide and pinned dock points on all four window sides so DockPane(s) can be pinned or auto hidden outside of the DocumentContainer(s). WindowsManager also contains the root DocumentContainer that can host documents in tab control or nested-split DocumentContainer instances hosting documents.

WindowsManager has the following properties:

  • DockPaneIllustrationStyle – Illustration for docking a window within WindowsManager or DocumentsContainer
  • DockIllustrationContentStyle – Illustration for merging documents while dragging a DockPane in TabControl
  • ActiveWindowsManager Static property indicating a WindowsManager undergoing the drag operation
  • DraggedPane DockPane that is being dragged
  • <Orientation>WindowHeaders StackPanel containing condensed auto-hidden DockPane(s)
  • <Orientation>PinnedWindows DockPanel containing pinned DockPane(s)
  • DocumentContainer – Root document container
  • DockingIllustrationPanel – Docking illustration panel for future pinned DockPanel(s)
  • PopupArea DockPanel where auto-hidden DockPane(s) slide out when mouse hovers upon the condensed headers
  • FloatingPanel Canvas that contains floating DockPane(s)
  • DockingPanel DockPanel that contains dock points for pinned windows as shown in image below:

7.png

WindowsManager has the following methods:

  • AddPinnedWindow(DockPane, Dock) – Adds a pinned DockPane
  • AddAutoHideWindow(DockPane, Dock) – Adds an auto-hidden DockPane
  • AddFloatingWindow(DockPane) – Adds a floating DockPane
  • RemoveDockPane(DockPane) – Removes a DockPane from (pinned, auto-hidden or floating portion of ) WindowsManager
  • Clear – Clears the WindowManager of all DockPane(s)
  • StartDockPaneStateChangeDetection – Starts state monitoring for DraggedPane
  • StopDockPaneStateChangeDetection – Stops state monitoring for DraggedPane

How It All Works Together

The image below illustrates the relationship between various components of the docking solution:

8.png

Structurally WindowsManager is the encompassing component that contains pinned and auto-hidden DockPane(s). It also contains the root DocumentContainer. DocumentContainer on the other hand can either contain documents in the tab control by wrapping DockPane within DocumentContent instance or it can contain split windows where a grid holds child DocumentContainer(s), each of which recursively can either contain documents or further child DocumentContainer(s).

WindowsManager constantly monitors the state change of DockPane. When a DockPane drag is detected, it is placed on the FloatingPanel canvas of WindowsManager as a floating window that can be dragged around. During a drag of a DockPane hit testing is turned off on the DockPane so mouse events can flow down to controls below it such as WindowsManager and DocumentContainer.

For orchestrating drag and drop and docking functionality, I have used a behavior driven approach. The idea is to expose functional end-points (such as methods and properties) on visual entities such as DockPane, DocumentContainer and WindowsManager and use behaviors to orchestrate and call these functional end-points. This approach also resulted in manageable-encapsulated components that were easier to trace and test.

DockPointBehavior monitors the dragged DockPane over WindowsManager and pops up dock points for pinning it. ContentPointBehavior on the other hand, injects similar functionality within DocumentContainer for splitting and tab merging purpose.

Both WindowsManager and DocumentContainer have dock illustration grid containing the docking behavior. DockPointBehavior behavior illustrates pinned docking illustration on WindowsManager whereas ContentDockBehavior illustrates splitting and tab merging illustration on DocumentContainer.

Using the Code

Using WindowsManager is extremely simple:

  • Import the namespace in the XAML:
    xmlns:visualFx="http://mixmodes.com/visualFx"  
  • Drop the WindowsManager in the XAML:
    <visualFx:WindowsManager x:Name="WindowsManager"/>  
  • Start creating DockPane and insert them within WindowsManager / DocumentContainer:
    DockPane pane = new DockPane();
    pane.Header = …  
    pane.Content = …. 
    WindowsManager.AddPinnedWindow(pane, Dock.Top); 
    // OR 
    WindowsManager.AddAutoHideWindow(pane, Dock.Left); 
    // OR 
    // Assuming DocumentContainer is either in Empty or ContainsDocuments state 
    WindowsManager.DocumentContainer.AddDocument(pane); 

Serializing Window State

Out of the box, Synergy provides XML serialization of window states through XmlWindowsManagerSerializer and XmlWindowsManagerDeserializer classes. Custom serialization is supported via specialization of base classes WindowsManagerSerializer and WindowsManagerDeserializer respectively.

XML serialization of WindowsManager using XmlWindowsManagerSerializer requires two pieces of information during construction:

  • DockPane writer – An Action<XmlElement, DockPane> instance that can write additional metadata about a DockPane to the XmlElement.

  • Document writer – A Func<DocumentContent, string> instance that takes in a DocumentContent and returns a string representation of the content. Note: DocumentContent.DockPane property returns the associated DockPane, however the Header and Content properties of DockPane are set to null. To access Header and Content property, use the Header and Content properties of DocumentContent instance directly.

Once XmlWindowsManagerSerializer instance is created, a call to Serialize(Stream, WindowsManager) method serializes WindowsManager to the stream.

Similar to serialization process, deserialization process requires an instance of Action<DockPane, string> within the constructor of XmlWindowsManagerDeserializer to de-serialize a DockPane from previously saved string representation. Deserialization does not require additional Action to realize DocumentContent since DocumentContent is inherently a serialization wrapper for DockPane.

Once XmlWindowsManagerDeserializer instance is created, a call to Deserialize(Stream, WindowsManager) deserializes the WindowsManager to previously saved state.

All the docking functionality can be exercised by using the sample app (Synergy project) with the source code. Any comments or suggestions or bug-reports are as usual always welcome. Happy coding!

License

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

About the Author

Ashish Kaila
Software Developer (Senior) MixModes Inc. | Research In Motion
Canada Canada
Member
Ashish worked for Microsoft for a number of years in Microsoft Visual Studio (Architect edition) and Windows Live division as a developer. Before that he was a developer consultant mainly involved in distributed service development / architecture. His main interests are distributed software architecture, patterns and practices and mobile device development.
 
Currently Ashish serves as a Technical Lead at RIM leading next generation BlackBerry media experience and also runs his own company MixModes Inc. specializing in .NET / WPF / Silverlight technologies. You can visit MixModes at http://mixmodes.com or follow it on Twitter @MixModes
 
In his free time he is an avid painter, hockey player and enjoys travelling. His blog is at: http://ashishkaila.serveblog.net

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5memberaqua98_15 May '13 - 17:23 
we
QuestionFramework 4.0memberasterix4513026 Feb '13 - 19:34 
Hello,
I have a problem with your source.
 
I work with c# Framework 4.0 beacause i must use dataGrid.
 
In Framework 4.0 your source is not correct. The dock doesn't work.
 
Do you have an idea ??
 
Thank you.
AnswerRe: Framework 4.0memberAshish Kaila27 Feb '13 - 7:43 
Can you be more clear in defining what does not work? Can you port the sample app to .NET 4.0 and see what happens?
Ashish Kaila

GeneralRe: Framework 4.0memberasterix451302 Mar '13 - 9:22 
Hello, before sory for my english. I try to describe my problem. When i opened your project with visual studio 2010, i love it. It's perfect. But for my application i must use datagrid. Si, i change the framework of all project to framework4.0. Your project compile. I think cool it's ok. But, when i want to deplace a windows, the Button top it's very large and mask all the form. Can you test it ? Think you
GeneralRe: Framework 4.0memberAshish Kaila2 Mar '13 - 9:46 
To be frank with my current schedule I won't be able to do it soon. You can download the source code and modify it as per your needs.
Ashish Kaila

GeneralMy vote of 5 [modified]memberARIA 52 Jan '13 - 1:14 
Hi Ashish Kiala,
this is great and nice work.
thanks,
i wish u best luck.

modified 5 Jan '13 - 4:46.

GeneralRe: My vote of 5memberAshish Kaila3 Jan '13 - 2:53 
Thanks Aria,
Let me know if you have any questions regarding its usage.
Ashish Kaila

GeneralI have a problemmemberARIA 54 Jan '13 - 23:39 
Hi Ashish,
Thanks, I am using your library and design my favorite Solution Explorer that contain a button with contextMenu,now when right click on the button to showing ContextMenu the ContextMenu is show but the Solution Explorer become hide,
it happen when the SolutionExplorer is auto hide.this does not occur in another mode,however i think when the contextMenu is displayed the SolutionExplorer lost focused,for this reason the solutioExplorer become hide.
please check it and tell how to fix this if possible.
best regards.
QuestionWanna know about this classes?membermdrizwan_12 May '12 - 1:07 
Hello Ashish,
 
Your project is wonderful. Can you please explain about this classes? ObservableDependencyProperty and ObservableDependencyPropertyCollection this two classes.
 
Regards
AnswerRe: Wanna know about this classes?memberAshish Kaila24 Dec '12 - 12:19 
These classes enable components to be notified when a dependency property or collection changes for properties and collections that the component does not own. Hope this helps.
Ashish Kaila

QuestionAdding DocumentsmemberRohit Dubey from Hyderabad7 Mar '12 - 13:23 
Hi there,
 
can you please provide an example of how to add a pane in "document mode" (in WPF)? I want a pane appear in Document state like in "Anatomy of Dockable Window", point 3.
 
I already tried to insert it within DocumentContainer like in your example:
 
WindowsManager.DocumentContainer.AddDocument(pane);
But this doesn't work because there's no DocumentContainer neither via the class WindowsManager.DocumentContainer nor the property _windowsManager.DocumentContainer.
 
I also tried to set the
new DockPane();
p.DockPaneState = DockPaneState.Content;
which showed no effect, either.
 
Can someone please help me on this?
AnswerRe: Adding DocumentsmemberAshish Kaila7 Mar '12 - 13:34 
You should be able to use:
WindowsManager.DocumentContainer.Documents.Add(...) to add your view model as a document.
 
If you look at the serialization and de-serialization code for windows manager and document container, it adds the documents in the tabs.
Ashish Kaila

GeneralRe: Adding Documents [modified]memberRohit Dubey from Hyderabad7 Mar '12 - 16:27 
No, I can't.
 
Typing this.WindowsManager.DocumentContainer says that DocumentContainer is an internal field which I can't access within an other project (in V1.0 and Codeplex-Changeset 12470).
 
I want to add dynamically panes, like in Point 3, to the DocumentContainer to have them as tabs. Would it be "safe" to make the DocumentContainer-Field public?

modified 7 Mar '12 - 22:50.

QuestionthankingmemberEhsanHejazi4 Mar '12 - 8:52 
I search for dockpanel about 1week but now I can find it in this place,Thanks very much...
AnswerRe: thankingmemberAshish Kaila4 Mar '12 - 9:08 
Thanks Ehsan,
Let me know how it fares for your project !
Ashish
Ashish Kaila

QuestionIs the usage as simple as author says? or I miss something? [modified]memberMorven Huang14 Feb '12 - 18:28 
I create a new project, add the reference, import the visualFx, add WindowsManager, initialize DockPane and invoke WindowsManager.AddPinnedWindow as author mentions in the article, and I get nothing, yes, nothing.
Am I miss something important?
 
---
I believe this has something to do with target framework, it works after I change the target framework of my project from .net 4 to .net 3.5.

modified 15 Feb '12 - 3:52.

QuestionObserve closingmemberda_boss19 Jul '11 - 19:05 
Hi there,
 
I am adding some UserControls to a DockedPane and I am observing their Close-Event to be able to reopen them if the user closes them.
 
But, of course, the user might also drag them to a DocumentContainer. Can I also observe if a DocumentContainer-Tab gets closed? Until now, I haven't found anything.
 
I want to observe the closing event, because I want to provide the possibility to open it again, when it gets closed but avoiding open more than one instance at a time.
AnswerRe: Observe closingmemberAshish Kaila20 Jul '11 - 10:43 
Hello there,
Thanks for reporting the bug. I have fixed it in the codeplex codebase[^]
Ashish
Ashish Kaila

GeneralRe: Observe closingmemberda_boss20 Jul '11 - 18:28 
Thank you very much for the quick fix, it's working now.
 
(Thanks also for this great toolkit Smile | :) )
QuestionTime neededmemberBuzal Thomas29 Jun '11 - 0:48 
Hi, this is a nice project and you wrote that this was a personal challenge and learning opportunity. Can you valuate how long you circa need for your first usable version?
AnswerRe: Time neededmemberAshish Kaila29 Jun '11 - 3:06 
You can download the WPF version at http://mixmodessynergy.codeplex.com. I will not be completing silverlight version due to MS dumping the technology.
Ashish Kaila

GeneralRe: Time neededmemberBuzal Thomas29 Jun '11 - 4:38 
Thx, for your fast answer and sry for my bad english. I mean how long did you need for this WPF project.
Generalwould thismemberInfinity82729 Jan '11 - 10:04 
would this work for forms? okay, for example:
I am going to make a form editor, would I be able to input a form into this control?
GeneralRe: would thismemberAshish Kaila29 Jan '11 - 11:10 
Yes you can embed any form of control(s) as the content of the panes.
Ashish Kaila

Generalsilverlightmembermeteor66628 Dec '10 - 0:51 
Hi
there's a project like this on codeplex.
Unfortunately, they have decided, the project to be avalaible also for winform. therefore the project is absolutely useless. Dead | X|
furthermore, it is impossible to decline a silverlight version.Mad | :mad:
It would be terrific if you decided not to make the same error. I would really thank you. Big Grin | :-D
And it would be terrific if you decided to make a silverlight version.Cool | :cool:
I am almost sure no to be good enough to help you in this adventure, but i will gladly test it for you Poke tongue | ;-P and more if can...
GeneralRe: silverlightmemberAshish Kaila28 Dec '10 - 4:32 
Hello there,
As I mentioned in the very beginning "I know there are many implementations of similar solutions out there, some even open source, but my aim was to take this personal project as a challenge and learning opportunity." I think it sums it all for you. I am soon going to implement the silverlight version. I would be glad if you decide to test any version and give me your feedback. Rest assured this will be very agile and responsive project.
Thanks,
Ashish
Ashish Kaila

GeneralRe: silverlightmemberskalkin13 Mar '12 - 5:14 
So I'm just wondering if you ported it to Silverlight already?
QuestionCS0162memberPaul Selormey27 Dec '10 - 15:30 
Is it only on my machine or you are also seeing the (10 in all)
warning CS0162: Unreachable code detected

and simply ignoring them?
 
Best regards,
Paul.
Jesus Christ is LOVE! Please tell somebody.

AnswerRe: CS0162memberAshish Kaila27 Dec '10 - 15:45 
No I am not seeing any warnings. I am using default warning level 4 on VS10 which is default for project.
Thanks,
Ashish
Ashish Kaila

QuestionRequiring Microsoft.Expression.Interactions and System.Windows.Interactivity?memberPaul Selormey27 Dec '10 - 12:30 
Are these not limitations you are putting on the use of your library?
 
Best regards,
Paul.
Jesus Christ is LOVE! Please tell somebody.

AnswerRe: Requiring Microsoft.Expression.Interactions and System.Windows.Interactivity?memberAshish Kaila27 Dec '10 - 14:32 
Hello Paul,
The assemblies you mentioned contain lots of reusable code from Microsoft's end and are meant to be redistributed with end applications. So I would not see it as a limitation. Microsoft is also proactively developing these assemblies so with time it will grow in terms of features. Here is a link you would want to refer in this regard: http://social.expression.microsoft.com/Forums/en/blend/thread/8523aec4-1a10-4864-8ad4-f95a3627bb4a
 
Also I have now included bin and debug folders in the zip file that includes these assemblies in case you don't have on your system Smile | :)
Thanks,
Ashish
Ashish Kaila

GeneralRe: Requiring Microsoft.Expression.Interactions and System.Windows.Interactivity?memberPaul Selormey27 Dec '10 - 15:19 
Thanks for the clarifications.
 
Ashish Kaila wrote:
Also I have now included bin and debug folders in the zip file that includes these assemblies in case you don't have on your system

Cool, initial attempt to compile failed, because I do not have Expression stuff on my home machine. Now, it should compile successfully.
 
Best regards,
Paul.
Jesus Christ is LOVE! Please tell somebody.

GeneralRe: Requiring Microsoft.Expression.Interactions and System.Windows.Interactivity? [modified]memberAshish Kaila27 Dec '10 - 15:43 
Yes I didn't realize so thanks for clean trial Smile | :) . You can always extract Microsoft dlls in a separate folder so they don't get washed away every time you do a clean build.
Thanks,
Ashish
Ashish Kaila
modified on Monday, December 27, 2010 10:05 PM

GeneralNicememberBillaBong27 Dec '10 - 10:13 
Very nice project! Thumbs Up | :thumbsup: Only got one exception; to replicate: freshly started application, add two "Solution explorers", dock one to the top, second - to the bottom of the main window, when any of those two are going to be closed using their "X" button NullReferenceException raises at DocumentContainer class, line 265, ReduceChild method call. I don't have much time now to find the cause, but I'll post more info if the above is not enough Smile | :)
GeneralRe: NicememberAshish Kaila27 Dec '10 - 14:32 
Thanks BillaBong for reporting the bug.
I have made the fix and re-uploaded the source code.
Thanks,
Ashish
Ashish Kaila

GeneralRe: NicememberBillaBong27 Dec '10 - 21:22 
Thanks, works perfectly now! +5

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

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130516.1 | Last Updated 1 Jan 2011
Article Copyright 2010 by Ashish Kaila
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid