How it started

One of the major disadvantages of the old docking framework was the unintuitive layout mechanism. Operations like resize, re-dock transitions, dock position change were re-setting entire layout scene and all user-defined sizes were lost. Having recognized this drawback and knowing that a prerequisite for a good docking framework is a fine-grained layout system, we put solid efforts in designing and implementing a completely new flexible and powerful, yet simple to understand and easy to use, layout mechanism.

Brief Model Overview

The design of the control is simple, yet flexible enough to handle virtually any complex layout scenario. The layout consists of one or more SplitPanel instances, organized in containers. A container has an “Orientation” property, which defines the direction in which each child panel will be laid-out. It also composes a SplitContainerLayoutStrategy instance, which handles all layout requests from its owning container. Each SplitPanel instance has a member of type SplitPanelSizeInfo, which is used by the strategy to determine the size and position of this panel on its hosting container. Available are four different sizing modes per panel basis:

1. Auto: a panel is auto-sized, based on the available remaining size of the container.

2. Relative: a panel occupies amount of space, relative to the container’s available size. This amount is specified through the SplitPanelSizeInfo.RelativeRatio property.

3. Absolute: Absolute size is used for a panel. The amount of size is specified through the SplitPanelSizeInfo.AbsoluteSize property.

4. Fill: Special mode currently used by the MainDocumentContainer in RadDock. When a RadSplitContainer has a descendant(s) with this special size mode, all panels are sized absolutely, leaving the available space for the “Fill” panel.

Having all these sizing modes, combined with the Orientation setting, available per split container basis, allow for virtually any layout scenario to be easily achieved.

Building a Grid of Panels

private
void CreateGrid(RadSplitContainer container, int cols, int rows, Orientation orientation, bool centerFill)
{
    container.Orientation = orientation;

    for (int i = 0; i < rows; i++)
    {
        RadSplitContainer newContainer = new RadSplitContainer();
        newContainer.Orientation = Orientation.Vertical;
        newContainer.SizeInfo.AbsoluteSize = new Size(100, 100);

 

        for (int j = 0; j < cols; j++)
        {
            SplitPanel panel = new SplitPanel();
            panel.SizeInfo.AbsoluteSize = new Size(100, 100);
            container.SplitPanels.Add(panel);
        }
        container.SplitPanels.Add(newContainer);
    }
    if (centerFill)
    {
        (container.SplitPanels[rows / 2] as RadSplitContainer).SplitPanels[cols / 2].SizeInfo.SizeMode = Telerik.WinControls.UI.Docking.SplitPanelSizeMode.Fill;
    }
}

What we are doing here is to create a number (specified by the “rows” parameter) of split containers and for each container to add the desired number (defined by the “cols” parameter) split panels. When we have a descendant split panel with Size Mode set to fill, then all other descendants are sized absolutely to allow the Fill panel occupy entire remaining size. The layout engine is smart enough to traverse the entire layout tree, thus allowing the fill panel to reside at any branch. Following is the result of the above code:

image
A 5*5 Grid of SplitPanel instances, with the center panel’s SizeMode set to SplitPanelSizeMode.Fill

If we do not apply the Fill size mode to the center panel, then we have evenly auto-sized panels:

image
A 3*3 Grid of SplitPanel instances, all auto-sized

Size Restrictions

private
void ApplyPanelRestrictions(SplitPanel panel, Size minSize, Size maxSize)
{
    SplitPanelSizeInfo sizeInfo = panel.SizeInfo;
    sizeInfo.MinimumSize = minSize;
    sizeInfo.MaximumSize = maxSize;
}

image
The green panel in the center is with applied size restrictions

These settings are considered by both the layout engine and the splitter logic, which will clamp the drag hint to visually emphasize on the restrictions.


This layout container may be used as a base for building complex composite controls/frameworks. For example our new RadDock uses RadSplitContainer instances to build its layout. Or you may easily mimic the layout of Microsoft Outlook. Well, that’s it folks, I do hope that you will find this new control useful.


Comments

Comments are disabled in preview mode.