【问题标题】:Abbreviate serialization in .Designer.Designer 中的缩写序列化
【发布时间】:2015-08-18 11:12:50
【问题描述】:

我有一个带有Foo 类型属性的自定义控件。我为这个类创建了一个UITypeEditor

这很有效,并导致设计器代码如下:

Dim Foo1 As PropertySerialization.Foo = New PropertySerialization.Foo()
Me.FooControl1 = New PropertySerialization.FooControl()
Me.SuspendLayout()
'
'FooControl1
'
Me.FooControl1.Location = New System.Drawing.Point(35, 56)
Me.FooControl1.Name = "FooControl1"
Me.FooControl1.Size = New System.Drawing.Size(188, 136)
Foo1.A = 3
Foo1.B = "World"
Me.FooControl1.Something = Foo1
Me.FooControl1.TabIndex = 0
Me.FooControl1.Text = "FooControl1"

Something 属性的类型为 Foo,如您所见,设计师明确创建了一个新对象 Foo1

我的问题是:我可以告诉设计者宁愿使用 With 关键字内联创建 foo 对象,例如:

'
'FooControl1
'
Me.FooControl1.Location = New System.Drawing.Point(35, 56)
Me.FooControl1.Name = "FooControl1"
Me.FooControl1.Size = New System.Drawing.Size(188, 136)
Me.FooControl1.Something = New Foo() With {.A = 3, .B = "World"}
Me.FooControl1.TabIndex = 0
Me.FooControl1.Text = "FooControl1"

当要创建更复杂的类型时,我希望这样可以避免设计器文件中的混乱。

非常感谢 C# 或 VB.NET 中的答案。

【问题讨论】:

  • 一个类型转换器会让你在那儿走得更远。设计师序列化是 VS 的工作,它会按照自己认为合适的方式进行。您可能至少可以使用 ctor 重载
  • 确实如此。我已经实现了这个(但在这个例子中废弃了它)但我遇到了问题,VS 然后 only 使用了构造函数并忽略了任何其他属性。不过,这可能是一个实施问题,因为我不太熟悉这些方式。
  • InstanceDescriptor 的最终 True/False 表示是否还有更多的 props 需要序列化
  • 哦,我忽略了这一点。谢谢,我会再检查一遍
  • 它仍然会创建一个显式的临时变量,所以它只会让你分道扬镳,其他道具上的 DesignerSerializationVisibility 设置也可能是一个因素

标签: .net vb.net visual-studio windows-forms-designer typeconverter


【解决方案1】:

设计师 (VS) 将按照自己的意愿将它写出来,很大程度上取决于您的 Foo 类型是如何构建的以及它继承自什么。但总的来说,您可以提供TypeConverter 并至少使用构造函数参数获得更短的形式。

这是通过在CanConvertToConvertTo 中回复InstanceDescriptor 来完成的:

<Serializable>
<TypeConverter(GetType(FooConverter))>
Public Class Foo
    Inherits ??????

   <DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)>
   Public Property Name As String

   <DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)>
   Public Property Value As Integer

   Public Sub New(newName As String, v As Integer)
        Name = newName
        Value = v
   End Sub

    ' simple constructor
    Public Sub New()
        Name = "New Foo"
        Value = 0
    End Sub
End Sub

HiddenDesignerSerializationVisibility 属性值告诉 VS 不要打扰序列化该属性。目的是通过重载的构造函数来处理它。类型转换器:

Friend Class FooConverter
    Inherits TypeConverter

    ' designer serialization will check to see if 
    ' there is a converter available
    Public Overrides Function CanConvertTo(context As ITypeDescriptorContext,
                                    destType As Type) As Boolean
        If destType = GetType(InstanceDescriptor) Then
            ' Yes I Can!
            Return True
        End If
        Return MyBase.CanConvertTo(context, destType)
    End Function

    Public Overrides Function ConvertTo(context As ITypeDescriptorContext,
                                        info As CultureInfo, value As Object,
                                        destType As Type) As Object

        If destType = GetType(InstanceDescriptor) Then
            Dim f As Foo = CType(value, Foo)

            ' prepare a constructor info
            Dim ctor As Reflection.ConstructorInfo

            ' the ctor wanted, is the one which takes a string, and an Integer
            ctor = GetType(Foo).GetConstructor(New Type() _
                          {GetType(String), GetType(Integer)})

            ' return Instance Descriptor built from ctor info and 
            '   an array of the current values for the ctor
            Return New InstanceDescriptor(ctor,
                        New Object() {f.Name, f.Value}, False)

        End If
        Return MyBase.ConvertTo(context, info, value, destType)
    End Function

End Class

为清楚起见,上面的内容是拼写出来的,但您可以使用简写:

Return New InstanceDescriptor(GetType(Foo). _
                              GetConstructor(New Type() _
       {GetType(String),
       GetType(Integer)}),
       New Object() {f.Name, f.Value}, False)

设计器代码结果仍然是一个显式的临时对象,但更紧凑,任何其他属性都将被一一设置:

Dim Foo1 As Prj.Foo = New Prj.Foo("Ziggy", 43)

注意后面的Boolean 参数表示VS 是否应该寻找更多的属性。 Boolean 和属性上的 DesignerSerializationVisibility 值的组合将确定 VS 是序列化这些值还是您的 TC 处理它。任何希望保留的值都应由您的 TypeConverter 处理或设置为 .Visible

最后没有关于自定义控件或真正的Foo 类型的信息,很难知道如何应用一些细节(什么是可序列化的等)。

摘自Enhanced CollectionEditor Framework,其中涵盖了简单的 TC 和设计器序列化。

就个人而言,只要 VS 通常会做的任何事情都会起作用,似乎需要做很多额外的工作。

【讨论】:

  • 我认为你是对的。似乎即使是 MS 控件也会导致对象的显式声明。我认为您已将其尽可能简短,并且您的 CodeProject 文章看起来很有趣,我将在下一篇文章中阅读。
猜你喜欢
  • 1970-01-01
  • 2019-12-06
  • 2014-06-07
  • 1970-01-01
  • 2016-04-07
  • 1970-01-01
  • 1970-01-01
  • 2017-05-17
  • 1970-01-01
相关资源
最近更新 更多