Click here to Skip to main content
11,647,828 members (61,506 online)
Click here to Skip to main content

Building a Docking Window Management Solution in WPF

, 1 Jan 2011 CPOL 77.4K 11K 76
Rate this:
Please Sign up or sign in to vote.
A docking window solution using WPF as part of Synergy toolkit

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 DockPanecontrol that is derivative of HeaderedContentControl. In addition to Headerand Contentproperties 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

DockPanealso 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 DockPaneis defined in the DockPane.xaml resource dictionary within MixModes.Synergy.Themesproject.

Document Containers

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

  • EmptyDocumentContainerdoes not contain any DockPane
  • ContainsDocumentsDocumentContainercontains one or more DockPane(s) as documents
  • SplitHorizontallyDocumentContaineris split horizontally
  • SplitVertically- DocumentContaineris split vertically

5.png

DocumentContaineris 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 TabControlwithin the template that is hidden if Contentproperty is ever non-null. Content of-course is used exclusively to contain split views via Gridwith two children DocumentContainer.

DocumentContainercontains the following properties:

  • State– State of the DocumentContainer
  • Documents– Contains documents represented in TabControl
  • DocumentsTabTabControlcontaining 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 DockPaneto any one of these points, it gets docked at the respective position. The image below shows content of the DockIllustrationPanel:

6.png

DocumentContainercontains the following methods:

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

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

  • TabControl (PART_DOCUMENTS)– Bound to Documentsproperty of DocumentContainer
  • ContentPresenter– This is where split children are added
  • Grid (PART_DOCK_POINTS)– Panel for hosting dock illustration points
  • Grid (PART_DOCK_ILLUSTRATION)DockIllustrationPanelfor 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). WindowsManageralso contains the root DocumentContainerthat can host documents in tab control or nested-split DocumentContainerinstances hosting documents.

WindowsManagerhas the following properties:

  • DockPaneIllustrationStyle– Illustration for docking a window within WindowsManageror DocumentsContainer
  • DockIllustrationContentStyle– Illustration for merging documents while dragging a DockPanein TabControl
  • ActiveWindowsManagerStaticproperty indicating a WindowsManagerundergoing the drag operation
  • DraggedPaneDockPanethat is being dragged
  • <Orientation>WindowHeadersStackPanelcontaining condensed auto-hidden DockPane(s)
  • <Orientation>PinnedWindowsDockPanelcontaining pinned DockPane(s)
  • DocumentContainer– Root document container
  • DockingIllustrationPanel– Docking illustration panel for future pinned DockPanel(s)
  • PopupAreaDockPanelwhere auto-hidden DockPane(s) slide out when mouse hovers upon the condensed headers
  • FloatingPanelCanvasthat contains floating DockPane(s)
  • DockingPanelDockPanelthat contains dock points for pinned windows as shown in image below:

7.png

WindowsManagerhas 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 DockPanefrom (pinned, auto-hidden or floating portion of ) WindowsManager
  • Clear– Clears the WindowManagerof 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 WindowsManageris the encompassing component that contains pinned and auto-hidden DockPane(s). It also contains the root DocumentContainer. DocumentContaineron the other hand can either contain documents in the tab control by wrapping DockPanewithin DocumentContentinstance 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).

WindowsManagerconstantly monitors the state change of DockPane. When a DockPanedrag is detected, it is placed on the FloatingPanelcanvas of WindowsManageras a floating window that can be dragged around. During a drag of a DockPanehit testing is turned off on the DockPaneso mouse events can flow down to controls below it such as WindowsManagerand 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, DocumentContainerand WindowsManagerand 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.

DockPointBehaviormonitors the dragged DockPaneover WindowsManagerand pops up dock points for pinning it. ContentPointBehavioron the other hand, injects similar functionality within DocumentContainerfor splitting and tab merging purpose.

Both WindowsManagerand DocumentContainerhave dock illustration grid containing the docking behavior. DockPointBehaviorbehavior illustrates pinned docking illustration on WindowsManagerwhereas ContentDockBehaviorillustrates splitting and tab merging illustration on DocumentContainer.

Using the Code

Using WindowsManageris extremely simple:

  • Import the namespace in the XAML:
    xmlns:visualFx="http://mixmodes.com/visualFx"
  • Drop the WindowsManagerin the XAML:
    <visualFx:WindowsManager x:Name="WindowsManager"/>
  • Start creating DockPaneand 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 XmlWindowsManagerSerializerand XmlWindowsManagerDeserializerclasses. Custom serialization is supported via specialization of base classes WindowsManagerSerializerand WindowsManagerDeserializerrespectively.

XML serialization of WindowsManagerusing XmlWindowsManagerSerializerrequires two pieces of information during construction:

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

  • Documentwriter – A Func<DocumentContent, string> instance that takes in a DocumentContentand returns a stringrepresentation of the content. Note: DocumentContent.DockPaneproperty returns the associated DockPane, however the Headerand Contentproperties of DockPaneare set to null. To access Headerand Contentproperty, use the Headerand Contentproperties of DocumentContentinstance directly.

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

Similar to serialization process, deserialization process requires an instance of Action<DockPane, string> within the constructor of XmlWindowsManagerDeserializerto de-serialize a DockPanefrom previously saved stringrepresentation. Deserialization does not require additional Actionto realize DocumentContentsince DocumentContentis inherently a serialization wrapper for DockPane.

Once XmlWindowsManagerDeserializerinstance is created, a call to Deserialize(Stream, WindowsManager) deserializes the WindowsManagerto 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)

Share

About the Author

Ashish Kaila
Software Developer (Senior) MixModes Inc. | Research In Motion
Canada Canada
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

You may also be interested in...

Comments and Discussions

 
GeneralMy vote of 5 Pin
ARIA 52-Jan-13 1:14
memberARIA 52-Jan-13 1:14 
GeneralRe: My vote of 5 Pin
Ashish Kaila3-Jan-13 2:53
memberAshish Kaila3-Jan-13 2:53 
GeneralI have a problem Pin
ARIA 54-Jan-13 23:39
memberARIA 54-Jan-13 23:39 

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
Web03 | 2.8.150804.4 | Last Updated 1 Jan 2011
Article Copyright 2010 by Ashish Kaila
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid