DXSerializer事件-高级场景
本主题描述DXSerializer事件的高级用例。
序列化/反序列化DevExpress WPF控件子类的自定义属性
保存/恢复自定义属性必须满足的要求
1.用[XtraSerializableProperty]属性标记属性。
在GridControl的后代中,您还应该为该属性分配以下属性之一:
- 当DXSerializer.StoreLayoutMode为UI时,[GridUIProperty]属性用于保存/恢复自定义属性。
- 当DXSerializer.StoreLayoutMode为None时,[GridStoreAlwaysProperty]属性用于保存/恢复自定义属性。
2.如果属性是依赖属性,请指定其本地值。
下面的代码示例保存/恢复MyCustomProperty依赖属性值:
XAML:
<Window xmlns:dx="//schemas.devexpress.com/winfx/2008/xaml/core" xmlns:local="clr-namespace:GridSerialization" xmlns:dxg="//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>
C# :
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.NET:
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
序列化自定义附加属性
要序列化自定义附加属性,请使用[xtrasserializableproperty]属性标记该属性的Get方法。
C# :
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.NET:
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
序列化标准和自定义控件
要保存/恢复自定义控件和标准控件的属性,请执行以下操作:
1.为要保存/恢复其布局的控件指定SerializationID属性。
2.用[XtraSerializableProperty]属性标记要保存/恢复其值的控件属性。
3.做以下其中一件事:
将属性传递给DXSerializer.AddCustomGetSerializablePropertiesHandler方法。
处理CustomGetSerializableProperties事件并将属性传递给CustomGetSerializablePropertiesEventArgs.SetPropertySerializable方法。
不恢复控件的预定义属性
执行以下操作来防止属性反序列化:
1.处理AllowProperty事件。
2.设置AllowPropertyEventArgs,允许属性为false。
您可以使用AllowPropertyEventArgs.Property来获得一个反序列化的属性。
下面的代码示例禁用了GridControl列的WidthProperty的反序列化操作:
MainWindow.xaml.cs:
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; } }
MainWindow.xaml.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
停止布局恢复(反序列化)
1.处理BeforeLoadLayout事件。
2.将BeforeLoadLayoutEventArgs.Allow事件参数设置为false。
下面的代码示例禁用GridControl的属性反序列化,如果布局版本不是1.48:
MainWindow.xaml.cs:
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; } } }
MainWindow.xaml.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
从已保存(序列化)集合恢复项
- 处理CreateCollectionItem事件。
- 创建要恢复的集合对象的实例。
- 将创建的实例添加到e.Collection事件参数中。
- 设置e.CollectionItem为创建对象的实例。
例如,GridControl处理此事件来恢复列、摘要项、MRU过滤器等。
如果属性被标记为[xtrasserialableproperty]属性,则引发此事件,XtraSerializableProperty.XtraSerializationVisibility属性必须设置为xXtraSerializationVisibility.Collection,XtraSerializableProperty.UseCreateItem属性应该设置为true。
C# :
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.NET:
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
保存可视树中不存在的控件
处理CustomGetSerializableChildren事件。
添加一个控件,它的布局要保存到CustomGetSerializableChildrenEventArgs.Children集合。
如果一个LayoutPanel包含一个UserControl和一个GridControl,并且这个面板没有被激活,GridControl在可视树中不存在,并且它的属性没有被保存(序列化)。要保存GridControl的属性,将GridControl添加到CustomGetSerializableChildrenEventArgs.Children集合中。
MainWindow.xaml.cs:
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); } }
MainWindow.xaml.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
序列化没有被xtrasserializable属性标记的属性
1.处理CustomGetSerializableProperties事件。
2.将要保存/恢复其值的属性传递给CustomGetSerializablePropertiesEventArgs.SetPropertySerializable方法。
下面的代码示例保存(序列化)GridColumn.Tag属性:
C# :
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.NET:
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
在应用程序的不同版本之间更新布局
执行以下操作并在较新的应用程序版本中更新应用程序的布局:
1.指定或增加DXSerializer.LayoutVersion附加的属性值,此属性是应用程序布局的版本。
2.更改应用程序的布局。
3.如果应用程序的DXSerializer.LayoutVersion附加属性值低于新属性值,则触发LayoutUpgrade事件。
提示:DXSerializer.AddXXXHandler方法只适用于UI元素。如果一个元素是FrameworkContentElement的后代,则使用标准的AddHandler方法。
创建自定义属性反序列化处理程序
当属性被反序列化时,将发生DeserializeProperty事件,您可以使用XtraPropertyInfoEventArgs.Name/XtraPropertyInfoEventArgs.DependencyProperty获取属性/依赖属性的名称。
XAML:
<Window ... xmlns:dx="//schemas.devexpress.com/winfx/2008/xaml/core" xmlns:dxg="//schemas.devexpress.com/winfx/2008/xaml/grid"> <DockPanel> <!-- ... --> <dxg:GridControl x:Name="grid" dx:DXSerializer.DeserializeProperty="grid_DeserializeProperty"> <!-- ... --> </dxg:GridControl> </DockPanel> </Window>
C# :
private void grid_DeserializeProperty(object sender, DevExpress.Xpf.Core.Serialization.XtraPropertyInfoEventArgs e) { if (e.DependencyProperty == ColumnBase.VisibleProperty) { e.Handled = true; // ... } }
VB.NET:
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