SandDock for Silverlight User Guide

Getting Started with Window Layouts

Back to Table of Contents

The DockSite

A window layout is synonymous with the DockSite class. This class shows all your docked tool windows around its edges, some content (optionally tabbed documents) in the middle, floating windows above all this, and interactive docking hints above those; while docking is taking place by the user. Your DockSite will normally occupy most of your root container. In a typical rich client application such as Visual Studio, the window contains some toolbars, a statusbar, and everything else is within the DockSite.

An example of a simple Silverlight page that contains only a SandDock DockSite and a rudimentary status bar is below.

<UserControl xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"  x:Class="DemoApplication.Page" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
    xmlns:sd="clr-namespace:Divelements.SandDock;assembly=Divelements.SandDock" 
    Width="800" Height="600" Loaded="OnLoaded"> 
    <Grid x:Name="LayoutRoot"> 
        <Grid.RowDefinitions> 
            <RowDefinition Height="*" /> 
            <RowDefinition Height="Auto" /> 
        </Grid.RowDefinitions> 
        <sd:DockSite Name="dockSite"> 
            <!-- content here --> 
        </sd:DockSite> 
        <TextBlock Grid.Row="1" Text="Ready" Padding="2" /> 
    </Grid> 
</UserControl>

ToolWindow and DocumentWindow

The SandDock classes that participate in window layouts are ToolWindow and DocumentWindow. You will generally use ToolWindow for dockable windows that contain tools that may need to be used from the main content or document that the user is working with. They are containers which accept one child, just like the main UserControl class that is used in Silverlight.

Both classes have a DockingRules property that accepts an instance of the DockingRules class. This simple class has AllowTab, AllowFloat, AllowDockLeft, AllowDockRight, AllowDockTop and AllowDockBottom properties that control how the user can interactively move the window within the layout. At this stage it is important to realize that DocumentWindow is simply a subclass of ToolWindow with different default docking rules: either window can be docked, tabbed or floated if its docking rules allow it. By default, tool windows can be docked and floated; document windows can only be tabbed.

Creating and showing a SandDock tool window at runtime is easy.

ToolWindow window = new ToolWindow(dockSite, "Example Window"); 
window.Open();

SplitContainer, DockedSplitContainer and WindowGroup

Window layouts can be complex in their nature. SandDock supports all the window layout flexibility of the Visual Studio shell. Our API makes manipulating windows very easy, but when creating a window layout in XAML you will need to use SplitContainer, DockedSplitContainer and WindowGroup to define the shape of your layout - at least until there are mature designer tools available for Silverlight. At that point, we'll make it very easy.

A SplitContainer is a primitive layout panel that displays its children with splitters between them to facilitate resizing, and the only children it supports are WindowGroup and more SplitContainers. A DockedSplitContainer is a root-level SplitContainer that lives at the side of your DockSite; it has a Dock property to govern which side it lives on and a ContentSize property to govern its size. A WindowGroup is the container that holds groups of your individual ToolWindow and DocumentWindow instances.

Both SplitContainer and WindowGroup have ProportionalSize properties. It is this property that governs the relative sizes of the elements within your layout. When the user resized docked windows using the splitters between them, this property is updated.

Imagine a window layout where on the right-hand side of your form there is WindowA and WindowB, in a group with tabs, and underneath them, WindowC is on its own. Comprising this layout are a DockedSplitContainer with its Dock property set to Right. Within that container are two WindowGroups, the first containing two windows and the second containing one. When only one window is contained in a group, the tabs are not shown by default. The XAML to achieve this layout at design-time follows.

<sd:DockSite Name="dockSite"> 
    <sd:DockedSplitContainer Dock="Right"> 
        <sd:WindowGroup> 
            <sd:ToolWindow Title="Window A" /> 
            <sd:ToolWindow Title="Window B" /> 
        </sd:WindowGroup> 
        <sd:WindowGroup> 
            <sd:ToolWindow Title="Window C" /> 
        </sd:WindowGroup> 
    </sd:DockedSplitContainer> 
</sd:DockSite>

This is pretty straightforward, as you can see. It only gets a little harder than this: we haven't used a SplitContainer on its own yet. This is used when instead of a WindowGroup you want two or more WindowGroups split down the middle. For example, if instead of Window C above we had two windows split, Window C and Window D. Because our DockedSplitContainer is docked on the right, its WindowGroups are laid out from top to bottom, with horizontal splitters in between. If you put a SplitContainer in, the new container lays out its children from left to right, with vertical splitters between. If you were to put another SplitContainer inside that one, the direction would reverse again, and so on.

<sd:DockSite Name="dockSite"> 
    <sd:DockedSplitContainer Dock="Right" ContentSize="200"> 
        <sd:WindowGroup> 
            <sd:ToolWindow Title="Window A" /> 
            <sd:ToolWindow Title="Window B" /> 
        </sd:WindowGroup> 
        <sd:SplitContainer> 
            <sd:WindowGroup> 
                <sd:ToolWindow Title="Window C" /> 
            </sd:WindowGroup> 
            <sd:WindowGroup> 
                <sd:ToolWindow Title="Window D" /> 
            </sd:WindowGroup> 
        </sd:SplitContainer> 
    </sd:DockedSplitContainer> 
</sd:DockSite>

DocumentContainer

You can have whatever content you like in the center of your DockSite. The content will always be resized to make way for the tool windows docked around the side. This will usually be the main functionality of your application.

If you want to use the tabbed document functionality that SandDock provides, you should use a DocumentContainer as the main content of your DockSite. This is actually a simple container that derives from SplitContainer, so as above you will it with WindowGroups and, optionally, further SplitContainers. Here's an example with a docked tool window on the right and a tabbed document taking center stage.

<sd:DockSite Name="dockSite"> 
    <sd:DockedSplitContainer> 
        <sd:WindowGroup> 
            <sd:ToolWindow Title="Tool Window" /> 
        </sd:WindowGroup> 
    </sd:DockedSplitContainer> 

    <sd:DocumentContainer> 
        <sd:WindowGroup> 
            <sd:DocumentWindow Title="Welcome!" /> 
        </sd:WindowGroup> 
    </sd:DocumentContainer> 
</sd:DockSite>

Because the document container is part of the flexible SandDock windowing system, it does a lot more than simply present a row of tabs. The user can grab a tab and drag it around to split all your documents into multiple viewing panes. They might choose to split the documents in half so they can work on one with reference to another; or have three open at the same time.

Normal Window Operations

The whole of the SandDock architecture is available for modifying at runtime, for fine-grained control over where every window goes. After all you can construct DockedSplitContainers and add them to the Items collection of your DockSite, construct a WindowGroup and add it to the Items collection of that DockedSplitContainer, and construct a ToolWindow and add it to the Items collection of that WindowGroup. This is, however, rather painful.

All the main window display functions can be distilled into a few methods on every window. The methods are outlined below.

Open Opens the window at its last known location, which can be floating, docked or tabbed. The window will always attempt to join the windows it was last with, or failing that, appear in approximately the same place, if window layout has changed since it was closed.
Close Closes the window. First the Closing event is raised, which give the developer the opportunity to cancel the closure. Then the window is hidden and the Closed event is raised. Then, if the CloseMethod is set to Detach (which it is on document windows by default) the window is unregistered from the DockSite altogether and is made available for garbage collection. The default value of this property on tool windows is Hide, and the window is kept around ready to be re-opened.
Hide Hides the window. This is different to closing the window: no events are raised and the window is always kept available for re-showing.
Float Opens the window in a floating state. The location and size of the window while floating can be set with the FloatingLocation and FloatingSize properties.
Dock Opens the window docked to the side of your container. One overload of this function accepts a variable specifying which side of the container the window is docked on. If this is not specified, the window opens on the side it was last docked on.
Document Opens the window as a tabbed document in the center of your layout. This function is only available if your layout contains a DocumentContainer; see the section on DocumentContainer.
OpenBeside Opens the window beside an existing window which is already open. This function takes a parameter specifying on which side of the existing window you want the new window opened.
OpenWith Opens the window grouped with a window which is already open.

Responding to Events

SandDock classes raise several events to keep your application in the loop concerning the window operations your user is engaged in. The DockSite class raises events that are typically handled on a layout-wide level, and individual windows raise events more usefully handled on a per-window basis. The following table outlines some of these events; your application will typically need to respond to at least one of them.

DockSite Events
DockingStartedRaised when the user has started dragging a window or group of windows and a docking operation has therefore commenced. Your application can show some helpful hints in the status bar for how to redock windows.
DockingStoppedRaised when the docking operation has stopped.
ToolWindow/DocumentWindow Events
ClosingRaised when the window is about to close, whether through the user clicking the close button or a call to its Close method. This event gives the application opportunity to cancel the closure of the window. This is often used to prompt whether to save changes as documents are being closed.
ClosedRaised after a window has been closed.
DockSituationChangedAll windows have a DockSituation property that indicates whether the window is Docked, Floating, a Tabbed Document or closed (None). This event is raised as the position of the window transitions between these states.

Next: Building a Complex Layout