自定义结构的设计器序列化

Designer serialization of custom structure

我有一个自定义结构:

Public Structure myStruct
   Public Sub New(ByVal row As Integer, ByVal Col As Integer)
      X = row : Y = Col
   End Sub
   Property X() As Integer
   Property Y() As Integer
end Structure

我在 UserControl 中用作 属性:

Public Class myUC
   inherits UserControl

   Property myProp1 As String = "test"
   Property MyProp2 As myStruct = New myStruct(1, 2)
End Class

如果我将此 UserControl 放在窗体上,Windows 窗体设计器将在 InitializeComponent 方法中创建一段代码,如下所示:

'
'MyUC1
'
Me.MyUC1.Location = New System.Drawing.Point(205, 187)
Me.MyUC1.myProp1 = "test"

Me.MyUC1.MyProp2 = CType(resources.GetObject("MyUC1.MyProp2"), WindowsApp11.myStruct)
Me.MyUC1.Name = "MyUC1"
Me.MyUC1.Size = New System.Drawing.Size(150, 150)
Me.MyUC1.TabIndex = 0

但我希望像 System.Drawing.Point 结构一样序列化 myStruct。因此生成的 Designer 代码应该是

'
'MyUC1
'
Me.MyUC1.Location = New System.Drawing.Point(205, 187)
Me.MyUC1.myProp1 = "test"
Me.MyUC1.MyProp2 = new WindowsApp11.myStruct(1,2)
Me.MyUC1.Name = "MyUC1"
Me.MyUC1.Size = New System.Drawing.Size(150, 150)
Me.MyUC1.TabIndex = 0

有谁知道如何告诉 Windows 表单设计器如何序列化自定义结构。我在考虑类似 Serialization.IXmlSerializable 接口的东西,但用于设计时。

我曾尝试使用 Google 查找内容,但我似乎使用了错误的搜索表达式。

感谢

您需要实现自定义 TypeConverter which can convert your object to InstanceDescriptor,然后设计人员使用您的结构的构造函数生成序列化代码。

为此,您需要派生自 TypeConverter 或派生自 TypeConverter 的 class 之一,例如 ExpandableObjectConverter,然后覆盖一些方法。

例子

  1. 创建一个 VB.NET Windows 表单应用程序。 (申请项目)

  2. 创建一个 VB.NET 控件库应用程序。 (控制项目)

  3. 添加 MyPoint.vb 并在其中粘贴以下代码以添加 MyPoint 结构和 MyPointConverter class:

     Imports System.ComponentModel
     Imports System.ComponentModel.Design.Serialization
     Imports System.Globalization
    
     <TypeConverter(GetType(MyPointConverter))>
     Public Structure MyPoint
         Public Property X As Integer
         Public Property Y As Integer
         Public Sub New(X As Integer, Y As Integer)
             Me.X = X
             Me.Y = Y
         End Sub
     End Structure
    
     Public Class MyPointConverter
         Inherits ExpandableObjectConverter
         Public Overrides Function CanConvertTo(context As ITypeDescriptorContext, destinationType As Type) As Boolean
             If destinationType = GetType(InstanceDescriptor) Then
                 Return True
             End If
             Return MyBase.CanConvertTo(context, destinationType)
         End Function
         Public Overrides Function ConvertTo(context As ITypeDescriptorContext, culture As CultureInfo, value As Object, destinationType As Type) As Object
             If destinationType = GetType(InstanceDescriptor) Then
                 Dim ci = GetType(MyPoint).GetConstructor(New Type() {GetType(Integer), GetType(Integer)})
                 MessageBox.Show(value.ToString())
                 Dim i = DirectCast(value, MyPoint)
                 Return New InstanceDescriptor(ci, New Object() {i.X, i.Y})
             End If
             Return MyBase.ConvertTo(context, culture, value, destinationType)
         End Function
         Public Overrides Function GetCreateInstanceSupported(context As ITypeDescriptorContext) As Boolean
             Return True
         End Function
         Public Overrides Function CreateInstance(context As ITypeDescriptorContext, propertyValues As IDictionary) As Object
             If (propertyValues Is Nothing) Then
                 Throw New ArgumentNullException(NameOf(propertyValues))
             End If
             Dim X = DirectCast(propertyValues(NameOf(MyPoint.X)), Integer)
             Dim Y = DirectCast(propertyValues(NameOf(MyPoint.Y)), Integer)
             Return New MyPoint(X, Y)
         End Function
     End Class
    
  4. 打开UserControl1.vb粘贴以下代码添加MyPoint属性:

     Public Class UserControl1
         Public Property MyPoint As MyPoint
     End Class
    
  5. 关闭所有设计器并重建解决方案。

  6. 打开第一个项目(应用程序项目)并在设计模式和工具箱中打开 Form1,删除 UserControl1 的实例,更改 MyPoint 属性 并保存更改。

  7. 查看 InitializeComponent 方法,您会看到:

     'UserControl11
     '
     Me.UserControl11.Location = New System.Drawing.Point(65, 65)
     Me.UserControl11.MyPoint = New WindowsControlLibrary1.MyPoint(1, 2)
     Me.UserControl11.Name = "UserControl11"
     Me.UserControl11.Size = New System.Drawing.Size(150, 150)
     Me.UserControl11.TabIndex = 2
    

提示

  1. 将控件放在与应用程序项目不同的项目中,以防止某些意外的设计器崩溃或序列化异常。

  2. 要清理 windows 表单设计器项目程序集,您需要删除 ProjectAssemblies 文件夹的子文件夹,该文件夹位于其中一个文件夹下的 %userprofile%\appdata\local\Microsoft\VisualStudio\ 中,具体取决于您的 visual studio 版本。对我来说,他们在这里:

     C:\Users\rag\AppData\Local\Microsoft\VisualStudio.0_dc21d183\ProjectAssemblies
    
  3. 如果您需要调试设计时,请按照此处说明的步骤操作: