New to Telerik UI for WPF? Download free 30-day trial

Save/Load Layout

This feature is available with R2 2016 Service pack 1 version of Telerik UI for WPF controls.

RadLayoutControl supports saving and loading the state of the layout. You can do this using the SaveToXmlString() and LoadFromXamlString() methods of RadLayoutControl. The control is serialized into an XML string and it is deserialized from one.

In order to serialize a layout you will need to set the RadLayoutControl.SerializationId attached property on the RadLayoutControl and all layout groups and UIElements that you want to save.

The SerializationId must be unique. If there are elements with matching SerializationId , this might lead to multiple operations performed on a single UI element resulting to an ArgumentException with the following error message: "Element is already the child of another element".

If an element doesn't have SerializationId property set, it will not be saved in the serialized XML file. So, it will be removed from the layout when the XML file loads.

Example 1: Setting SerializationId in XAML

<telerik:RadLayoutControl telerik:RadLayoutControl.SerializationId="myLayoutControlID" /> 

When moving an element (via drag and drop) that doesn't have a LayoutControlGroup parent, the element is automatically wrapped in a LayoutControlGroup which is added in the RadLayoutControl and marked as automatically generated.

Saving the layout

The layout can be saved via the SaveToXmlString() method.

Example 2: Saving the layout

string serializationString = this.layoutControl.SaveToXmlString(); 

The groups that are generated automatically at runtime are also serialized, but their SerializationId is not set. If you want the serialization/deserialization to work properly you will need to manually set the SerializationId in the ElementSaving event of RadLayoutControl.

Example 3: Setting SerializationId in code

private void layoutControl_ElementSaving(object sender, Telerik.Windows.Controls.LayoutControl.Serialization.LayoutElementSavingEventArgs e) 
{ 
    string serializationId = RadLayoutControl.GetSerializationId(e.Element); 
    if (String.IsNullOrEmpty(serializationId)) 
    { 
        serializationId = Guid.NewGuid().ToString(); 
        RadLayoutControl.SetSerializationId(e.Element, serializationId); 
    } 
} 

Loading the layout

The layout can be saved via the LoadFromXmlString() method.

Example 4: Loading the layout

this.layoutControl.LoadFromXmlString(serializationString); 

Loading elements removed from the visual tree

By default the RadLayoutControl will loaded only items which are in the visual tree. This means that if you remove element from the visual tree and then try to load the control, this element will not be loaded.

The serialization process saves only the state of element presented in the visual tree. If the deserialized element is removed from the tree, a new instance won't be created.

To load an element, which has been removed between the save and load process, you can subscribe to the ElementLoading event for this purpose. This event occurs when an element loading operation starts. For any element that is no presented in the visual tree the e.Element property from the event arguments will be Null. You can use this to create a new instance of the removed element and assign it on the e.Element property. The type of the currently loaded element can be get from the e.Info property from the event arguments.

Example 5: Create new instance of the removed element

private void LayoutControl_ElementLoading(object sender, Telerik.Windows.Controls.LayoutControl.Serialization.LayoutElementLoadingEventArgs e) 
    { 
        if (e.Element == null) 
        { 
            e.Element = CreateElementByType(e.Info["Type"]); 
        } 
    } 
 
    private FrameworkElement CreateElementByType(object type) 
    { 
        if (type.Equals("Telerik.Windows.Controls.LayoutControlGroup")) 
        { 
            return new LayoutControlGroup(); 
        } 
        else if (type.Equals("Telerik.Windows.Controls.LayoutControlExpanderGroup")) 
        { 
            return new LayoutControlExpanderGroup(); 
        } 
        else if (type.Equals("Telerik.Windows.Controls.LayoutControlTabGroup")) 
        { 
            return new LayoutControlTabGroup(); 
        } 
        else if (type.Equals("Telerik.Windows.Controls.LayoutControl.LayoutControlSplitter")) 
        {                 
            return new LayoutControlSplitter(); 
        } 
        return null; 
    } 

List of default saved properties

The serialization process automatically saves the following common properties of RadLayoutControl, all UIElements and layout groups that participate in the layout.

  • Width
  • Height
  • MinWidth
  • MinHeight
  • HorizontalAlignment
  • VerticalAlignment
  • RadLayoutControl.SerializationId

The serialization saves the Orientation and IsAutoGenerated properties of RadLayoutControl and all layout groups. There are few additional properties specific for the different layout groups that are saved. You can find them in the following list.

  • RadLayoutControl
    • IsInEditMode
  • LayoutControlExpanderGroup
    • Header
    • IsExpanded
    • IsExpandable
  • LayoutControlTabGroupItem
    • Header
    • Content
    • IsSelected

The Header and Content properties are serialized if they contain an object of type FrameworkElement or a layout group. You can nest layout groups inside other layout groups placed in the Header or Content property and the control will successfully save/load the hierarchy. If the value of the Header/Content property is not FrameworkElement or a layout group, it will be saved as a string.

You can see how to save custom properties or replace the value of a serialized/deserialized property in the Save custom properties section of this article.

Events

RadLayoutControl exposes several events relevant to the serialization process. They are fired for each saved element from the layout.

  • ElementSaving: This event occurs when an element saving operation starts. It can be used to cancel the saving process. The event arguments are of type LayoutElementSavingEventArgs and expose the following properties:

    • Cancel: A bool property that gets or sets whether the serialization should be canceled.
    • Element: A property of type FrameworkElement that gets the element that is currently being saved.
    • Info: A property of type SerializationInfo that gets the information that is saved. At this point the serialization info is empty.
  • ElementSaved: This event occurs when the saving operation is complete and the element is saved. The event arguments are of type LayoutElementSerializationEventArgs and expose the following properties:

    • Element: A property of type FrameworkElement that gets the saved element.
    • Info: A property of type SerializationInfo that gets the information that is saved.
  • ElementLoading: This event occurs when an element loading operation starts. It can be used to cancel the loading process. The event arguments are of type LayoutElementLoadingEventArgs and expose the following properties:

    • Cancel: A bool property that gets or sets whether the deserialization should be canceled.
    • Element: A property of type FrameworkElement that gets the element that is currently being loaded.
    • Info: A property of type SerializationInfo that gets the information that is loaded.
  • ElementLoaded: This event occurs when the loading operation is complete and the element is loaded. The event arguments are of type LayoutElementSerializationEventArgs and expose the following properties:

    • Element: A property of type FrameworkElement that gets the loaded element.
    • Info: A property of type SerializationInfo that gets the information that is loaded.

Saving and loading custom properties

You can use the ElementSaving or the ElementSaved events to save a custom property. And then ElementLoading or ElementLoaded to load it.

Example 6: Saving custom property

private void layoutControl_ElementSaving(object sender, Telerik.Windows.Controls.LayoutControl.Serialization.LayoutElementSavingEventArgs e) 
{ 
    // save a custom property 
    e.Info["Opacity"] = e.Element.Opacity; 
} 
 
private void layoutControl_ElementLoading(object sender, Telerik.Windows.Controls.LayoutControl.Serialization.LayoutElementLoadingEventArgs e) 
{ 
    // load and set the property 
    var opacity = e.Info["Opacity"]; 
    e.Element.Opacity = double.Parse(opacity.ToString()); 
} 

You can also use the serialization events to replace the value of any of the automatically saved/loaded properties.

Example 7: Replacing the value of a saved property

private void layoutControl_ElementSaved(object sender, Telerik.Windows.Controls.LayoutControl.Serialization.LayoutElementSerializationEventArgs e) 
{ 
    // replace the value of the VerticalAlignment property saved in the SerializationInfo object 
    e.Info["VerticalAlignment"] = VerticalAlignment.Top;         
} 

Note that you can use the Element property of the ElementLoading event arguments and replace it with another element. This could be useful in a scenario where the Element property is null.

Cancel saving and loading

You can use the ElementLoading and ElementSaving events to prevent the serialization/deserialization process.

Example 8: Cancel loading

private void layoutControl_ElementLoading(object sender, Telerik.Windows.Controls.LayoutControl.Serialization.LayoutElementLoadingEventArgs e) 
{    
    e.Cancel = true; 
} 

The elements in the RadLayoutControl are cleared before the ElementLoading event is invoked. If you cancel it the corresponding element (e.Element) won't be re-added in the visual tree.

Example 9: Cancel saving

private void layoutControl_ElementSaving(object sender, Telerik.Windows.Controls.LayoutControl.Serialization.LayoutElementSavingEventArgs e) 
{ 
    e.Cancel = true;     
} 


Generated XML string

This section demonstrate how the saved XML string is structured.

Saving the layout defined in Example 10 will generated the XML from Example 10. You can notice the LayoutControlGroup with x:Name="layoutControlGroup_3" was not serialized.

Example 10: LayoutControl defined in XAML

<telerik:RadLayoutControl x:Name="layoutControl" telerik:RadLayoutControl.SerializationId="myLayoutControlID"> 
    <Button Content="Button" telerik:RadLayoutControl.SerializationId="buttonID_1"/> 
    <Border Background="Bisque" telerik:RadLayoutControl.SerializationId="buttonID_2"/> 
    <telerik:LayoutControlGroup Orientation="Vertical" telerik:RadLayoutControl.SerializationId="layoutGroup_1"> 
        <TextBlock Text="TextBlock" Background="LightGray" TextAlignment="Center" VerticalAlignment="Center" telerik:RadLayoutControl.SerializationId="txtBlock_1" /> 
        <telerik:LayoutControlGroup Orientation="Vertical" VerticalAlignment="Center" Margin="2" telerik:RadLayoutControl.SerializationId="layoutGroup_2"> 
            <TextBlock Text="Text field:" Margin="5 0 5 0" telerik:RadLayoutControl.SerializationId="txtBlock_2" /> 
            <telerik:LayoutControlGroup Orientation="Vertical" VerticalAlignment="Center" Margin="2" > 
                <TextBlock Text="Text field:" Margin="5 0 5 0"  /> 
            </telerik:LayoutControlGroup> 
        </telerik:LayoutControlGroup> 
    </telerik:LayoutControlGroup> 
</telerik:RadLayoutControl> 

Example 11: Generated XML string

<?xml version="1.0" encoding="utf-8"?> 
<RadLayoutControl Type="Telerik.Windows.Controls.RadLayoutControl" Width="NaN" Height="NaN" MinWidth="0" MinHeight="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" SerializationId="myLayoutControlID" Orientation="Horizontal" IsAutoGenerated="false" IsInEditMode="false"> 
  <Items> 
    <Button Type="System.Windows.Controls.Button" Width="NaN" Height="NaN" MinWidth="0" MinHeight="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" SerializationId="buttonID_1" /> 
    <Border Type="System.Windows.Controls.Border" Width="NaN" Height="NaN" MinWidth="0" MinHeight="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" SerializationId="buttonID_2" /> 
    <LayoutControlGroup Type="Telerik.Windows.Controls.LayoutControlGroup" Width="NaN" Height="NaN" MinWidth="0" MinHeight="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" SerializationId="layoutGroup_1" Orientation="Vertical" IsAutoGenerated="false"> 
      <Items> 
        <TextBlock Type="System.Windows.Controls.TextBlock" Width="NaN" Height="NaN" MinWidth="0" MinHeight="0" HorizontalAlignment="Stretch" VerticalAlignment="Center" SerializationId="txtBlock_1" /> 
        <LayoutControlGroup Type="Telerik.Windows.Controls.LayoutControlGroup" Width="NaN" Height="NaN" MinWidth="0" MinHeight="0" HorizontalAlignment="Stretch" VerticalAlignment="Center" SerializationId="layoutGroup_2" Orientation="Vertical" IsAutoGenerated="false"> 
          <Items> 
            <TextBlock Type="System.Windows.Controls.TextBlock" Width="NaN" Height="NaN" MinWidth="0" MinHeight="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" SerializationId="txtBlock_2" /> 
          </Items> 
        </LayoutControlGroup> 
      </Items> 
    </LayoutControlGroup> 
  </Items> 
</RadLayoutControl> 

See Also

In this article