Wpf – Implementing a multidock window system (like blend, visual studio) in WPF

dockingwindowswpf

How would you go about to implement a docking toolbox windowing system as seen in Expression Blend where you can dock toolbox windows in a lot of ways beneat each other, overlapping as tabs or as floating top level windows. My system should behave pretty much the same as in Expression Blend. Also the way I get visual cues where the toolbox window would dock when dragging is exactly what I need.

There is just one exeception: In blend when dragging onto a toolbox window that is already top level (torn off) I can only dock it as a tab filling the whole window. I however need a system where there is no difference between a toolbox window and the main window. I need to be able to dock the windows beneath each other in a toolbox window just as in the main window.

Also note that due to an internal policy I can not use any open source or 3rd party library for this.

I'd be interested in how you would setup the general class design for something like this? I would like to stay as generic as possible so it can be used for lot of different scenarios.

The dockeing behavior is as in the following picture. The center image shows the sensetive drag docking region. And the outer images where the window would snap:

alt text http://img196.imageshack.us/img196/2450/dockingregions.png

Generally I am facing to mayor problems here: How do I design the programming model (how are the docking configurations to be persisted in XAML) and how do I acutally implement the underlying functionality. My first tought would be that I'd like to habe a symbiosis of a DockPanel and a TabControl. Something in the lines of this:

<DockTabControl>
  <DockTabItem Dock="FirstLeft">
    <DockTabItem.Header>
        <TextBlock>Tab 1</TextBlock>
    </DockTabItem.Header>
    <!-- Tab 1 content -->
  </DockTabItem>
  <DockTabItem Header="Tab 2" Dock="SecondLeft" DockMode="MergeWithPreviousToTabgroup">
    <!-- Tab 2 content -->
  </DockTabItem>
  <DockTabItem Header="Tab 3" Dock="FirstMiddle">
    <!-- Tab 3 content -->
  </DockTabItem>
</DockTabControl>

Of course this doesn't make sense yet. Docking can't be defined that way and the windowing problem is not adressed here yet. But I like the idea of defining the docking and the tabgroups just by defining some properties on the DockTabItem. I really wouldn't want to introduce extra controls like TabGroups or similar. I like how the docking behavior in the DockPanel just by defining the order of the children and the Dock attached property. Of course my docking will be a bit more complex and behaves more like what the Grid does.

Best Answer

To support the scenarios you illustrate in your question a single DockPanel would suffice, so all you need to write is handlers for OnDragEnter, OnDragOver, OnDragLeave, and OnDragDrop. I generally use a single event handler because the handling of these four events is so similar:

OnDragEnter & OnDragOver:

  1. Compute which edge and which location in DockPanel the item will be dropped
  2. Remove any existing adorner
  3. Add rectangular adorner to show drop location

OnDragLeave:

  1. Remove any existing adorner

OnDragDrop:

  1. Remove any existing adorner
  2. Compute which edge and which location in DockPanel the item will be dropped
  3. Remove dragged item from current panel, set DockPanel.Dock on it, and add it to new panel

Naturally you also have to handle dragging on the title bar and call DoDragDrop on the source object.

The two complexities here are:

  • Deciding whether a DockPanel is sufficient for your needs or if you will need a more complex data structure
  • Making sure the geometric calculations take into account all possible configurations of windows

For a simple algorithm I would estimate it would take a week to get all the wrinkles ironed out. If you need a really complex data structure and the structure itself is unobvious, it could take serious time to figure that part out.

Related Topic