Back to Devexpress

DXSerializer Events - Advanced Scenarios

wpf-7410-common-concepts-saving-and-restoring-layouts-advanced-scenarios.md

latest18.8 KB
Original Source

DXSerializer Events - Advanced Scenarios

  • Jul 27, 2025
  • 7 minutes to read

This topic describes advanced use cases of the DXSerializer‘s events.

Serialize/Deserialize Custom Properties of a DevExpress WPF Control Descendant

Requirements that Custom Properties Must Meet to be Saved/Restored

  1. Mark the property with the [XtraSerializableProperty] attribute.

  2. If your property is a dependency property, specify its local value.

Example

The following code sample saves/restores the MyCustomProperty dependency property value:

xaml
<Window
    xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"
    xmlns:local="clr-namespace:GridSerialization"
    xmlns:dxg="http://schemas.devexpress.com/winfx/2008/xaml/grid"
    x:Class="GridSerialization.MainWindow">
    <StackPanel>
        <local:GridControlEx dx:DXSerializer.StoreLayoutMode="UI" x:Name="grid" MyCustomProperty="15">
            <dxg:GridControl.View>
                <dxg:TableView/>
            </dxg:GridControl.View>
        </local:GridControlEx>
    </StackPanel>
</Window>
csharp
using DevExpress.Utils.Serializing;
using DevExpress.Xpf.Grid;
using DevExpress.Xpf.Core.Serialization;

public class GridControlEx : GridControl {

    public static DependencyProperty MyCustomPropertyProperty =
        DependencyProperty.Register("MyCustomProperty", typeof(int), typeof(GridControlEx));

    [XtraSerializableProperty]
    [GridStoreAlwaysProperty]
    public int MyCustomProperty {
        get => (int)GetValue(MyCustomPropertyProperty);
        set => SetValue(MyCustomPropertyProperty, value);
    }
}
vb
Imports DevExpress.Utils.Serializing
Imports DevExpress.Xpf.Grid
Imports DevExpress.Xpf.Core.Serialization

Public Class GridControlEx
    Inherits GridControl

    Public Shared MyCustomPropertyProperty As DependencyProperty = DependencyProperty.Register("MyCustomProperty", GetType(Integer), GetType(GridControlEx))

    <XtraSerializableProperty>
    <GridStoreAlwaysProperty>
    Public Property MyCustomProperty As Integer
        Get
            Return CInt(GetValue(MyCustomPropertyProperty))
        End Get
        Set(ByVal value As Integer)
            Return SetValue(MyCustomPropertyProperty, value)
        End Set
    End Property
End Class

Serialize Custom Attached Properties

To serialize a custom attached property, mark the property’s Get method with the [XtraSerializableProperty] attribute.

csharp
public static readonly DependencyProperty IsCheckedProperty =
    DependencyProperty.RegisterAttached("IsChecked", typeof(bool), typeof(GridControlEx), new PropertyMetadata(false));

[XtraSerializableProperty]
public static bool GetIsChecked(DependencyObject obj) {
    return (bool)obj.GetValue(IsCheckedProperty);
}
public static void SetIsChecked(DependencyObject obj, bool value) {
    obj.SetValue(IsCheckedProperty, value);
}
vb
Public Shared ReadOnly IsCheckedProperty As DependencyProperty = DependencyProperty.RegisterAttached("IsChecked", GetType(Boolean), GetType(GridControlEx), New PropertyMetadata(False))

<XtraSerializableProperty>
Public Shared Function GetIsChecked(ByVal obj As DependencyObject) As Boolean
    Return CBool(obj.GetValue(IsCheckedProperty))
End Function

Public Shared Sub SetIsChecked(ByVal obj As DependencyObject, ByVal value As Boolean)
    obj.SetValue(IsCheckedProperty, value)
End Sub

Serialize Standard and Custom Controls

To save/restore properties of custom and standard controls, do the following:

  1. Specify the SerializationID property for a control whose layout you want to save/restore.
  2. Mark the control’s properties whose values you want to save/restore with the [XtraSerializableProperty] attribute.
  3. Do one of the following:

Do not Restore a Control’s Predefined Property

Do the following to prevent a property from deserialization:

  1. Handle the AllowProperty event.
  2. Set the AllowPropertyEventArgs.Allow property to false.

You can use AllowPropertyEventArgs.Property to get a deserialized property.

The following code sample disables the deserialization operation for the GridControl column’s WidthProperty:

csharp
using DevExpress.Xpf.Core.Serialization;
using DevExpress.Xpf.Grid;
// ...

public partial class MainWindow : Window {
    public MainWindow() {
        //...
        grid.Columns[nameof(Customer.ID)].AddHandler(DXSerializer.AllowPropertyEvent, 
              new AllowPropertyEventHandler(OnAllowProperty));
    }

    void OnAllowProperty(object sender, AllowPropertyEventArgs e) {
        if (e.DependencyProperty == GridColumn.WidthProperty)
            e.Allow = false;
    }
}
vb
Imports DevExpress.Xpf.Core.Serialization
Imports DevExpress.Xpf.Grid
'...

Public Partial Class MainWindow
    Inherits Window

    Public Sub New()
        ' ...
        grid.Columns(NameOf(Customer.ID)).[AddHandler](DXSerializer.AllowPropertyEvent, 
            New AllowPropertyEventHandler(AddressOf OnAllowProperty))
    End Sub

    Private Sub OnAllowProperty(ByVal sender As Object, ByVal e As AllowPropertyEventArgs)
        If e.DependencyProperty = GridColumn.WidthProperty Then e.Allow = False
    End Sub
End Class

View Example: Do not serialize a GridControl's properties

Stop Layout Restore (Deserialization)

  1. Handle the BeforeLoadLayout event.
  2. Set the BeforeLoadLayoutEventArgs.Allow event argument to false.

The following code sample disables the GridControl‘s property deserialization if the layout version is not 1.48:

csharp
using DevExpress.Utils.Serializing;
using DevExpress.Xpf.Core.Serialization;
using DevExpress.Xpf.Grid;
using DevExpress.Xpf.Core;
// ...

public partial class MainWindow : Window {
    public MainWindow() {
        //...
        grid.AddHandler(DXSerializer.BeforeLoadLayoutEvent, new BeforeLoadLayoutEventHandler(BeforeLoadLayoutHandler));
    }

    void BeforeLoadLayoutHandler(object sender, BeforeLoadLayoutEventArgs e) {
        if (e.RestoredVersion != "1.48") {
               e.Allow = false;
        }
    }
}
vb
Imports DevExpress.Utils.Serializing
Imports DevExpress.Xpf.Core.Serialization
Imports DevExpress.Xpf.Grid
Imports DevExpress.Xpf.Core
'...

Public Partial Class MainWindow
    Inherits Window

    Public Sub New()
        InitializeComponent()
        Me.DataContext = Me
        grid.[AddHandler](DXSerializer.BeforeLoadLayoutEvent, New BeforeLoadLayoutEventHandler(AddressOf BeforeLoadLayoutHandler))
    End Sub

    Sub BeforeLoadLayoutHandler(ByVal sender As Object, ByVal e As BeforeLoadLayoutEventArgs)
        e.Allow = False
    End Sub
End Class

Restore Items From a Saved (Serialized) Collection

  1. Handle the CreateCollectionItem event.
  2. Create an instance of the collection object that you want to restore.
  3. Add the created instance to the e.Collection event argument.
  4. Set the e.CollectionItem to the created object’s instance.

For example, the GridControl handles this event to restore columns, summary items, MRU filters, and so on.

This event is raised if a property is marked with the [XtraSerializableProperty] attribute. The XtraSerializableProperty.XtraSerializationVisibility property must be set to XtraSerializationVisibility.Collection and the XtraSerializableProperty.UseCreateItem property should be set to true.

csharp
using DevExpress.Utils.Serializing;
using DevExpress.Xpf.Core.Serialization;
using DevExpress.Xpf.Grid;
using DevExpress.Xpf.Core;
// ...

public partial class MainWindow : Window {
    public MainWindow() {
        //...
        grid.Columns["Name"].AddHandler(DXSerializer.CreateCollectionItemEvent, new XtraCreateCollectionItemEventHandler(OnCreateCollectionItem));
    }

    void OnCreateCollectionItem(object sender, XtraCreateCollectionItemEventArgs e) {
        if (e.CollectionName == nameof(MyGridColumn.SomeCollection)) {
            CustomObject item = new CustomObject();
            ((ObservableCollection<CustomObject>)e.Collection).Add(item);
            e.CollectionItem = item;
        }
    }

    public class MyGridColumn : GridColumn {
        [XtraSerializableProperty(XtraSerializationVisibility.Collection, true, false, true)]
        public ObservableCollection<CustomObject> SomeCollection {
            get { return (ObservableCollection<CustomObject>)GetValue(SomeCollectionProperty); }
            set { SetValue(SomeCollectionProperty, value); }
        }

        public static readonly DependencyProperty SomeCollectionProperty = DependencyProperty.Register("SomeCollection", typeof(ObservableCollection<CustomObject>), typeof(MyGridColumn), null);
    }   

     public class CustomObject : INotifyPropertyChanged {
        string itemID;
        string itemValue;
        [XtraSerializableProperty]
        public string ItemID {
            get {
                return itemID;
            }
            set {
                itemID = value;
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs("ItemID"));
            }
        }
        [XtraSerializableProperty]
        public string ItemValue {
            get {
                return itemValue;
            }
            set {
                itemValue = value;
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs("PropertyB"));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        public void RaisePropertyChanged(string propertyName) {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    public class Customer {
        public int ID {
            get;
            set;
        }
        public string Name {
            get;
            set;
        }
    }
}
vb
Imports DevExpress.Utils.Serializing
Imports DevExpress.Xpf.Core.Serialization
Imports DevExpress.Xpf.Grid
Imports DevExpress.Xpf.Core

Public Partial Class MainWindow
    Inherits Window

    Public Sub New()
        grid.Columns("Name").[AddHandler](DXSerializer.CreateCollectionItemEvent, New XtraCreateCollectionItemEventHandler(AddressOf OnCreateCollectionItem))
    End Sub

    Private Sub OnCreateCollectionItem(ByVal sender As Object, ByVal e As XtraCreateCollectionItemEventArgs)
        Dim item As CustomObject = New CustomObject()
        (CType(e.Collection, ObservableCollection(Of CustomObject))).Add(item)
        e.CollectionItem = item
    End Sub
End Class

Save Controls that do not Exist in the Visual Tree

  1. Handle the CustomGetSerializableChildren event.
  2. Add a control whose layout you want to save to the CustomGetSerializableChildrenEventArgs.Children collection.

If a LayoutPanel contains a UserControl with a GridControl and this panel is not activated, the GridControl does not exist in the visual tree and its properties are not saved (serialized). To save a GridControl‘s properties, add the GridControl to the CustomGetSerializableChildrenEventArgs.Children collection.

csharp
using DevExpress.Utils.Serializing;
using DevExpress.Xpf.Core.Serialization;
using DevExpress.Xpf.Grid;
using DevExpress.Xpf.Core;
using DevExpress.Xpf.Docking;
// ...

public partial class MainWindow : Window {
    public MainWindow() {
        //...
        layoutPanel.AddHandler(DXSerializer.CustomGetSerializableChildrenEvent, new CustomGetSerializableChildrenEventHandler(CustomGetSerializableChildrenEventHandler));
    }
    ///...
    void OnCreateContentPropertyValue(object sender, XtraCreateContentPropertyValueEventArgs e) {
        e.Children.Add(grid);
    }
}
vb
Imports DevExpress.Utils.Serializing
Imports DevExpress.Xpf.Core.Serialization
Imports DevExpress.Xpf.Grid
Imports DevExpress.Xpf.Core
Imports DevExpress.Xpf.Docking
'...
Public Partial Class MainWindow
    Inherits Window

    Public Sub New()
        '...
        layoutPanel.[AddHandler](DXSerializer.CustomGetSerializableChildrenEvent, New CustomGetSerializableChildrenEventHandler(CustomGetSerializableChildrenEventHandler))
    End Sub
    '...
    Sub OnCreateContentPropertyValue(ByVal sender As Object, ByVal e As XtraCreateContentPropertyValueEventArgs)
        e.Children.Add(grid)
    End Sub
End Class

Serialize Properties that are not Marked with the XtraSerializablePropertyAttribute

  1. Handle the CustomGetSerializableProperties event.
  2. Pass the property whose value you want to save/restore to the CustomGetSerializablePropertiesEventArgs.SetPropertySerializable method.

The following code sample saves (serializes) the GridColumn.Tag property:

csharp
using DevExpress.Utils.Serializing;
using DevExpress.Xpf.Core.Serialization;
using DevExpress.Xpf.Grid;
using DevExpress.Xpf.Core;
//...
public partial class MainWindow : Window {
    public MainWindow() {
        //...
        grid.AddHandler(DXSerializer.CustomGetSerializablePropertiesEvent, new CustomGetSerializablePropertiesEventHandler(CustomGetSerializablePropertiesHandler));
    }

    void CustomGetSerializablePropertiesHandler(object sender, CustomGetSerializablePropertiesEventArgs e) {
        e.SetPropertySerializable(GridColumn.TagProperty, new DXSerializable() { });
    }
}
vb
Imports DevExpress.Utils.Serializing
Imports DevExpress.Xpf.Core.Serialization
Imports DevExpress.Xpf.Grid
Imports DevExpress.Xpf.Core
'...

Public Partial Class MainWindow
    Inherits Window

    Public Sub New()
        InitializeComponent()
        Me.DataContext = Me
        grid.[AddHandler](DXSerializer.CustomGetSerializablePropertiesEvent, New CustomGetSerializablePropertiesEventHandler(CustomGetSerializablePropertiesHandler))
    End Sub

    Sub CustomGetSerializablePropertiesHandler(ByVal sender As Object, ByVal e As CustomGetSerializablePropertiesEventArgs)
        e.SetPropertySerializable(GridColumn.TagProperty, New DXSerializable())
    End Sub
End Class

Update Layout Between Different Versions of Your Application

Do the following to update your application’s layout in a newer application version:

  1. Specify or increment the DXSerializer.LayoutVersion attached property value. This property is the version of your application’s layout.
  2. Change your application’s layout.
  3. If the DXSerializer.LayoutVersion attached property value of your application is lower than the new property value, the LayoutUpgrade event is fired.

View Example: How to use the LayoutUpgrade event to upgrade a layout from one version to another

Note

The DXSerializer.AddXXXHandler methods work only for UIElements. If an element is a FrameworkContentElement descendant, use the standard AddHandler method.

Create a Custom Property Deserialization Handler

The DeserializeProperty event occurs when a property is deserialized. You can use XtraPropertyInfoEventArgs.Name/XtraPropertyInfoEventArgs.DependencyProperty to get a name of a property/dependency property.

xaml
<Window ...
    xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"
    xmlns:dxg="http://schemas.devexpress.com/winfx/2008/xaml/grid">
    <DockPanel>
        <!-- ... -->
        <dxg:GridControl x:Name="grid" dx:DXSerializer.DeserializeProperty="grid_DeserializeProperty">
            <!-- ... -->
        </dxg:GridControl>
    </DockPanel>
</Window>
csharp
private void grid_DeserializeProperty(object sender, DevExpress.Xpf.Core.Serialization.XtraPropertyInfoEventArgs e) {
    if (e.DependencyProperty == ColumnBase.VisibleProperty) {
        e.Handled = true;
        // ...
    }
}
vb
Private Sub grid_DeserializeProperty(ByVal sender As Object, ByVal e As DevExpress.Xpf.Core.Serialization.XtraPropertyInfoEventArgs)
    If e.DependencyProperty = ColumnBase.VisibleProperty Then
        e.Handled = True
        '...
    End If
End Sub