Overview

When building complex layout with RadDocking, the users will often expect to persist the layout from one session to another. This can be easily achieved with the advanced Save/Load layout mechanism of the RadDocking.

The purpose of this tutorial is to show how to use the Save/Load layout mechanism of the RadDocking. The following cases will be examined:

Telerik UI for WPF Ninja image

The Save/Load Layout is part of Telerik UI for WPF, a professional grade UI library with 160+ components for building modern and feature-rich applications. To try it out sign up for a free 30-day trial.

Create a new application and add the following initial RadDocking declaration.

<telerik:RadDocking x:Name="radDocking"> 
    <telerik:RadDocking.DocumentHost> 
 
        <telerik:RadSplitContainer> 
            <telerik:RadPaneGroup x:Name="DocumentGroup"> 
                <telerik:RadPane x:Name="LayoutXml" Header="Layout Xml" 
telerik:RadDocking.FloatingSize="450, 400"> 
                    <TextBox TextWrapping="Wrap" x:Name="XmlTextBox" 
VerticalScrollBarVisibility="Auto" 
Text="{Binding Xml, Mode=TwoWay}" /> 
                </telerik:RadPane> 
                <telerik:RadDocumentPane Header="Document 1" Title="Document 1"> 
                    <TextBox x:Name="DocumentTextBox" Text="Some text" /> 
                </telerik:RadDocumentPane> 
            </telerik:RadPaneGroup> 
        </telerik:RadSplitContainer> 
 
    </telerik:RadDocking.DocumentHost> 
 
    <telerik:RadSplitContainer InitialPosition="DockedLeft"> 
        <telerik:RadPaneGroup> 
            <telerik:RadPane Header="Pane Left 1"> 
                <TextBox x:Name="TextBox" Text="Some other text" /> 
            </telerik:RadPane> 
            <telerik:RadPane Header="Pane Left 2"> 
                <TextBox Text="Pane Left 2" /> 
            </telerik:RadPane> 
            <telerik:RadPane Header="Pane Left 3"> 
                <TextBox Text="Pane Left 3" /> 
            </telerik:RadPane> 
            <telerik:RadPane Header="Pane Left 4"> 
                <TextBox Text="Pane Left 4" /> 
            </telerik:RadPane> 
        </telerik:RadPaneGroup> 
    </telerik:RadSplitContainer> 
 
    <telerik:RadSplitContainer InitialPosition="DockedRight"> 
        <telerik:RadPaneGroup> 
            <telerik:RadPane Header="Pane Right 1"> 
                <telerik:RadTreeView> 
                    <telerik:RadTreeViewItem Header="RootItem"> 
                        <telerik:RadTreeViewItem Header="Item1" /> 
                        <telerik:RadTreeViewItem Header="Item2"> 
                            <telerik:RadTreeViewItem Header="Item21" /> 
                            <telerik:RadTreeViewItem Header="Item22" /> 
                            <telerik:RadTreeViewItem Header="Item23"> 
                                <telerik:RadTreeViewItem Header="Item231" /> 
                            </telerik:RadTreeViewItem> 
                        </telerik:RadTreeViewItem> 
                        <telerik:RadTreeViewItem Header="Item3" /> 
                    </telerik:RadTreeViewItem> 
                </telerik:RadTreeView> 
            </telerik:RadPane> 
        </telerik:RadPaneGroup> 
    </telerik:RadSplitContainer> 
 
    <telerik:RadSplitContainer InitialPosition="DockedTop"> 
        <telerik:RadPaneGroup> 
            <telerik:RadPane Header="Pane Top 1"> 
                <TextBox Text="Pane Top 1" /> 
            </telerik:RadPane> 
        </telerik:RadPaneGroup> 
    </telerik:RadSplitContainer> 
</telerik:RadDocking> 
WPF RadDocking Initial Layout

Saving Layout

RadDocking gives you the ability to store the entire layout in a stream containing XML. In order to do that you need to use the SaveLayout method of an instance of the RadDocking control. Additionally, you can choose to save the stream elsewhere, in a textbox, or directly in the file system.

Perform the following steps:

Set the RadDocking.SerializationTag attached property for each one of the panes in your xaml declaration. If the SerializationTag is not set the Panes will be removed and new components will be created when the layout is loaded. If you want to preserve not only the Panes and load the same instances when the layout is loading you need to set the SerializationTag to all other components of RadDocking you want to preserve as well (RadPaneGroups, RadSplitContainers, RadPanes).

<telerik:RadPane x:Name="LayoutXml1" Header="Layout Xml" 
                 telerik:RadDocking.SerializationTag="LayoutXml" 
                 telerik:RadDocking.FloatingSize="450, 400"/> 
<telerik:RadDocumentPane Header="Document 1" Title="Document 1" 
                         telerik:RadDocking.SerializationTag="DocumentPane"/> 
<telerik:RadPane Header="Pane Left 1" 
                telerik:RadDocking.SerializationTag="PaneLeft1"/> 
<telerik:RadPane Header="Pane Left 2" 
                telerik:RadDocking.SerializationTag="PaneLeft2"/> 
<telerik:RadPane Header="Pane Left 3" 
                telerik:RadDocking.SerializationTag="PaneLeft3"/> 
<telerik:RadPane Header="Pane Left 4" 
                telerik:RadDocking.SerializationTag="PaneLeft4"/> 
<telerik:RadPane Header="Pane Right 1" 
                telerik:RadDocking.SerializationTag="PaneRight1"/> 
<telerik:RadPane Header="Pane Top 1" 
                telerik:RadDocking.SerializationTag="PaneTop1"/> 
Use the SaveLayout method of the RadDocking class. The following example demonstrates how to save the RadDocking layout in the IsolatedStorage. The generated XML is returned as well.

private string SaveLayout() 
{ 
    string xml; 
    // Save your layout for example in the isolated storage. 
    using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForAssembly()) 
    { 
        using (var isoStream = storage.OpenFile("RadDocking_Layout.xml", FileMode.Create)) 
        { 
            this.radDocking.SaveLayout(isoStream); 
            isoStream.Seek(0, SeekOrigin.Begin); 
            StreamReader reader = new StreamReader(isoStream); 
            xml = reader.ReadToEnd(); 
        } 
    } 
    // Return the generated XML 
    return xml; 
} 
Private Function SaveLayout() As String 
    Dim xml As String 
    ' Save your layout for example in the isolated storage. 
    Using storage As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForAssembly() 
        Using isoStream = storage.OpenFile("RadDocking_Layout.xml", FileMode.Create) 
            Me.radDocking.SaveLayout(isoStream) 
            isoStream.Seek(0, SeekOrigin.Begin) 
            Dim reader As New StreamReader(isoStream) 
            xml = reader.ReadToEnd() 
        End Using 
    End Using 
    ' Return the generated XML 
    Return xml 
End Function 

Here is how the result XML will look like for the above example:

<RadDocking> 
    <DocumentHost> 
        <RadSplitContainer Dock="DockedLeft"> 
            <Items> 
                <RadPaneGroup SelectedIndex="-1"> 
                    <Items> 
                        <RadPane SerializationTag="LayoutXml" IsDockable="True" Header="Layout Xml" /> 
                        <RadDocumentPane SerializationTag="DocumentPane" IsDockable="True" Title="Document 1" Header="Document 1" /> 
                    </Items> 
                </RadPaneGroup> 
            </Items> 
        </RadSplitContainer> 
    </DocumentHost> 
    <SplitContainers> 
        <RadSplitContainer Dock="DockedLeft"> 
            <Items> 
                <RadPaneGroup SelectedIndex="-1"> 
                    <Items> 
                        <RadPane SerializationTag="PaneLeft1" IsDockable="True" Header="Pane Left 1" /> 
                        <RadPane SerializationTag="PaneLeft2" IsDockable="True" Header="Pane Left 2" /> 
                        <RadPane SerializationTag="PaneLeft3" IsDockable="True" Header="Pane Left 3" /> 
                        <RadPane SerializationTag="PaneLeft4" IsDockable="True" Header="Pane Left 4" /> 
                    </Items> 
                </RadPaneGroup> 
            </Items> 
        </RadSplitContainer> 
        <RadSplitContainer Dock="DockedRight"> 
            <Items> 
                <RadPaneGroup SelectedIndex="-1"> 
                    <Items> 
                        <RadPane SerializationTag="PaneRight1" IsDockable="True" Header="Pane Right 1" /> 
                    </Items> 
                </RadPaneGroup> 
            </Items> 
        </RadSplitContainer> 
        <RadSplitContainer Dock="DockedTop"> 
            <Items> 
                <RadPaneGroup SelectedIndex="-1"> 
                    <Items> 
                        <RadPane SerializationTag="PaneTop1" IsDockable="True" Header="Pane Top 1" /> 
                    </Items> 
                </RadPaneGroup> 
            </Items> 
        </RadSplitContainer> 
    </SplitContainers> 
</RadDocking> 

There are two steps you should perform in order to save your layout (and one more that is optional):

  1. Mark all RadPanes with the RadDocking.SerializationTag.
  2. Use the SaveLayout method of the RadDocking to save your layout in a stream.
  3. (Optional) Save the stream in the isolated storage.

When you load the layout, all the elements that are not marked with SerializationTag property are removed and new components are created instead. That is the reason why you should mark your panes with the SerializationTag attribute.

Load Layout

In order to load the docking layout you need to do absolutely the same things but in reverse order.

  • First, load the stream (e.g. from the isolated storage).

  • Second, use the LoadLayout method of the RadDocking control.

private void LoadLayout() 
{ 
    // Load your layout from the isolated storage. 
    using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForAssembly()) 
    { 
        using (var isoStream = storage.OpenFile("RadDocking_Layout.xml", FileMode.Open)) 
        { 
            this.radDocking.LoadLayout(isoStream); 
        } 
    } 
} 
Private Sub LoadLayout() 
    ' Load your layout from the isolated storage. 
    Using storage As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForAssembly() 
        Using isoStream = storage.OpenFile("RadDocking_Layout.xml", FileMode.Open) 
            Me.radDocking.LoadLayout(isoStream) 
        End Using 
    End Using 
End Sub 

Events

The RadDocking API offers you six events for managing the save/load layout behavior:

  • ElementLoading - raised when a docking element (Pane, PaneGroup or SplitContainer) is about to be loaded. The type of the passed event arguments is LayoutSerializationLoadingEventArgs.

    • LayoutSerializationLoadingEventArgs - provides access to the AffectedElement, AffectedElementSerializationTag, ElementProperties properties and the Cancel property that determines whether the AffectedElement will be loaded.
  • ElementLoaded- raised after a docking element (Pane, PaneGroup or SplitContainer) is loaded. The type of the passed event arguments is LayoutSerializationEventArgs.

  • ElementSaving - raised when a docking element (Pane, PaneGroup or SplitContainer) is about to be saved. The type of the passed event arguments is LayoutSerializationEventArgs.

  • ElementLayoutSaving (introduced with R2 2016 of UI for WPF) - raised when a docking element (Pane, PaneGroup or SplitContainer) is about to be saved. The type of the passed event arguments is LayoutSerializationSavingEventArgs.

    • LayoutSerializationSavingEventArgs - provides access to the AffectedElement, AffectedElementSerializationTag, ElementProperties properties and the Cancel property that determines whether the AffectedElement will be serialized.
  • ElementSaved - raised after a docking element (Pane, PaneGroup or SplitContainer) is saved. The type of the passed event arguments is LayoutSerializationEventArgs.

  • ElementCleaning- raised when a docking element (Pane, PaneGroup or SplitContainer) is about to be cleaned. The type of the passed event arguments is LayoutSerializationEventArgs.

  • ElementLayoutCleaning (introduced with R2 2016 of UI for WPF) - raised when a docking element (Pane, PaneGroup or SplitContainer) is about to be cleaned. The type of the passed event arguments is LayoutSerializationCleaningEventArgs.

    • LayoutSerializationCleaningEventArgs - provides access to the AffectedElement, AffectedElementSerializationTag properties and the Cancel property that determines whether the AffectedElement will be removed from the layout.
  • ElementCleaned- raised after a docking element (Pane, PaneGroup or SplitContainer) is cleaned. The type of the passed event arguments is LayoutSerializationEventArgs.

  • CustomElementLoading- raised when a custom docking element (that derives from RadPane, RadPaneGroup or RadSplitContainer) is about to be loaded. The type of the passed event arguments is LayoutSerializationCustomLoadingEventArgs.

The type of the event arguments for the ElementLoaded, ElementSaving, ElementSaved, ElementCleaning and ElementCleaned is: Telerik.Windows.Controls.LayoutSerializationEventArgs. Via both of the event arguments you get access to the following properties:

  • AffectedElement- this is the currently loaded\saved pane.

  • AffectedElementSerializationTag- this is the currently loaded\save serialization tag. In the previous example if you attach to any of the events, then the first time when the AffectedElementSerializationTag is fired, it will have the value "LayoutXml".

  • ElementProperties - this is a Dictionary that contains the string representations of the DependencyPropertys of the AffectedElement that will be saved to the layout Xml of the RadDocking.

The event argument of the CustomElementLoading event is of type LayoutSerializationCustomLoadingEventArgs that derives from the LayoutSerializationLoadingEventArgs and adds the following additional properties:

  • CustomElementTypeName - it gets the type name of the custom affected element.

  • Cancel - determines whether the custom AffectedElement will be loaded.

The Telerik.Windows.Controls.LayoutSerializationLoadingEventArgs allows you to point out an instance to be used as a newly loaded control. This could be useful if you need to create the instances yourself.

You have the ability to "say" whether these event to be fired or not, when the SerializationTag is not specified. You should use the second overload of the LoadLayout and SaveLayout methods.

public void SaveLayout(Stream destination, bool raiseEventsIfNoSerializationTag) 
{ 
 
} 
Public Sub SaveLayout(ByVal destination As Stream, ByVal raiseEventsIfNoSerializationTag As Boolean) 
End Sub 

By default when you use the SaveLayout method only the layout (without the content) will be saved. That's why the most common use of the fourth events is to save (respectively load) the pane's content. In order to see how to do that take a look at the Save/Load the Content of the Panes topic.

See Also

In this article