WPF SplitContainer

by Weifen Luo (DevZest) 7. August 2009 17:50

SplitContainer

Introduction

Windows Forms has a very handy SplitContainer control that you can use to resize two child panels. In WPF world we're out of the luck - we must use Grid and GridSplitter which is not intuive, and most importantly, can only data binding to a collection of children instead of the fixed number of 2. As we all know, data binding is the bridge between Model and View in WPF, and the greatest part (at least from my point of view) is the seperation of Model and View (or named as business logic and presentation).

So we decided to develop a custom panel (SplitContainer class) just like Windows Forms SplitContainer, which resizes two children as the value of Child1 and Child2 dependency property. It also supports auto-resize by double clicking the splitter, resizing by keyboard arrow keys, etc. The splitter, and resizing preview, can be fully customized (see Point of Interest). You can build endless layout complexity by nesting more SplitContainers.

The SplitContainer is part of our commercial product WPF Docking, a undo/redo-able docking library for WPF, as a Free Feature that you can use FREE OF CHARGE for both commercial and non-commercial applications. We decided to make this class open source as a contribution to the WPF development community.

Please note the downloadable source code is under GPL license and cannot be used for proprietary software. To use SplitContainer for proprietary software, you can download and install our WPF Dockingproduct, and obtain a Free Feature License through installed License Console, FREE OF CHARGE. This additional couple of clicks brings you extra benefits of commercial product quality documentation, upgrade and free technical support.

Using SplitContainer

Using SplitContainer is simple and intuitive. The following XAML code demonstrates the usage of SplitContainer:

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:dz="http://schemas.devzest.com/presentation"
    Title="SplitContainer Demo"
    Width="300" Height="300">
    <dz:SplitContainer>
        <dz:SplitContainer.Child1>
            <Button Content="Button1"/>
        </dz:SplitContainer.Child1>
        <dz:SplitContainer.Child2>
            <dz:SplitContainer Orientation="Horizontal" ShowsPreview="False">
                <dz:SplitContainer.Child1>
                    <Button Content="Button2"/>
                </dz:SplitContainer.Child1>
                <dz:SplitContainer.Child2>
                    <Button Content="Button3"/>
                </dz:SplitContainer.Child2>
            </dz:SplitContainer>
        </dz:SplitContainer.Child2>
    </dz:SplitContainer>
</Window>

You may find detailed information from our online documentation, or from the WPF Docking product documentation installed locally.

Customizing the Splitter

The following content requires intermediate or advanced WPF knowledge: styling, templating and adorner.

Everything in WPF should be customizable. Our SplitContainer makes no exception. You can customize the splitter and resizing preview through the SplitterTemplate dependency property. The splitter is a ContentPresenter with its Content property set to this SplitContainer, and its ContentTemplate property set to the value of SplitterTemplate property:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:common="clr-namespace:DevZest.Windows">

    <Style TargetType="common:SplitContainer">
        <Style.Resources>
            <Style TargetType="Rectangle" x:Key="SplitterStyle">
                <Setter Property="Fill" Value="{Binding SplitterBackground}" />
                <Setter Property="Focusable" Value="True" />
            </Style>

            <DataTemplate x:Key="SplitterAdornerTemplate">
                <Rectangle x:Name="rectangle" DataContext="{Binding DataContext}"
                    Opacity="{Binding PreviewOpacity}"
                    Fill="{Binding PreviewBackground}">
                    <Rectangle.RenderTransform>
                        <TranslateTransform X="{Binding PreviewOffsetX}" Y="{Binding PreviewOffsetY}" />
                    </Rectangle.RenderTransform>
                </Rectangle>
            </DataTemplate>
        </Style.Resources>

        <Setter Property="SplitterTemplate">
            <Setter.Value>
                <DataTemplate>
                    <Rectangle x:Name="splitter" Style="{StaticResource SplitterStyle}" />
                    <DataTemplate.Triggers>
                        <DataTrigger Binding="{Binding Orientation}" Value="Horizontal">
                            <Setter TargetName="splitter" Property="Cursor" Value="SizeWE" />
                        </DataTrigger>
                        <DataTrigger Binding="{Binding Orientation}" Value="Vertical">
                            <Setter TargetName="splitter" Property="Cursor" Value="SizeNS" />
                        </DataTrigger>
                        <DataTrigger Binding="{Binding IsPreviewVisible}" Value="True">
                            <Setter TargetName="splitter" Property="common:AdornerManager.AdornerTemplate" Value="{StaticResource SplitterAdornerTemplate}" />
                        </DataTrigger>
                    </DataTemplate.Triggers>
                </DataTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

Two points of the above XAML code:

First, we introduced AdornerManager class, which has two attached properties: AdornerManager.Adorner and AdornerManager.AdornerTemplate, that you can use to declare an UIElement or DataTemplate as adorner of a given FrameworkElement, in XAML.

Second, note how the cursor is set based on the Orientation property value and how the adorner element (a semi-transparent rectangle) is binding to the IsPreviewVisible, PreviewOffsetX and PreviewOffsetY properties.

Although not recommended, you have the freedom to make the splitter and resizing preview of your SplitContainer really fancy, by overriding the default style.

Tags: , , ,

Freebies | WPF

Comments

8/7/2009 5:57:37 PM #

WPF SplitContainer

You've been kicked (a good thing) - Trackback from DotNetKicks.com

DotNetKicks.com |

Comments are closed

Copyright DevZest, 2008 - 2017