【问题标题】:Designer serialization of custom structure自定义结构的设计器序列化
【发布时间】:2021-01-07 15:47:15
【问题描述】:

我有一个自定义结构:

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

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

'
'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 查找内容,但我似乎使用了错误的搜索表达式。

谢谢

【问题讨论】:

  • 你需要实现一个类型转换器并重写一些方法。您将在this answer 中找到一个示例。
  • 这里是source code of PointConverter。此功能的关键方法是GetCreateInstanceSupportedCreateInstance
  • 我重新打开,因为这是一个 VB 问题。
  • 谢谢你。这正是我正在寻找的解决方案!它就像一个魅力!
  • 没问题,我贴了一个VB答案来帮助以后的读者。

标签: .net vb.net winforms windows-forms-designer


【解决方案1】:

您需要实现一个自定义的TypeConverter,它可以将您的对象转换为InstanceDescriptor,然后设计器使用您的结构的构造函数生成序列化代码。

为此,您需要派生自TypeConverter 或派生自TypeConverter 的类之一,例如ExpandableObjectConverter,然后重写一些方法。

示例

  1. 创建一个 VB.NET Windows 窗体应用程序。 (应用项目)

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

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

     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\16.0_dc21d183\ProjectAssemblies
    
  3. 如果您需要调试设计时间,请按照此处说明的步骤操作:How to debug WinForms designer

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多