【问题标题】:VB.Net items added via the designer not reflected on code通过设计器添加的 VB.Net 项目未反映在代码中
【发布时间】:2023-03-09 10:45:02
【问题描述】:

我有一个用户控件,它公开了自定义集合的属性。

这是用户控件中使用的代码。

Imports System.ComponentModel.DesignerSerializationVisibility

Public Class textbox
    Inherits System.Windows.Forms.TextBox
    Private _validation As New validationList

    <System.ComponentModel.DesignerSerializationVisibility(Content)>
    Public Property Validation As validationList
        Get
            Return _validation
        End Get
        Set(ByVal value As validationList)
            _validation = value
        End Set
    End Property
End Class

这是该属性使用的集合类。

Imports System.Collections.ObjectModel
<Serializable()> Public Class validationList
    Inherits Collection(Of validationItem)

    Public Shadows Sub Add(ByVal item As validationItem)
        '//Check for duplicates
        Dim dupe As Boolean = False
        For n As Int32 = 0 To Items.Count - 1
            If Items(n).Key = item.Key Then
                dupe = True
                Exit For
            End If
        Next
        If dupe = False Then
            Items.Add(item)
        End If
    End Sub
End Class

这里是集合类使用的项目列表

<Serializable()> Public Class validationItem
    Private _key As validationTypes
    Private _value As String

    Public Sub New()
        '//Empty constructor is needed for serialization
    End Sub

    Public Sub New(ByVal k As validationTypes, ByVal v As String)
        _key = k
        _value = v
    End Sub

    Public Enum validationTypes
        Madatory = 1
        [Integer] = 2
        Numeric = 3
        [Decimal] = 4
        MaxValue = 5
        MinValue = 6
        MinLength = 7
        Email = 8
    End Enum

    Public Property Value As String
        Get
            Return _value
        End Get
        Set(ByVal Value As String)
            _value = Value
        End Set
    End Property

    Public Property Key As validationTypes
        Get
            Return _key
        End Get
        Set(ByVal value As validationTypes)
            _key = value
        End Set
    End Property
End Class

这是实现 Pluntonix 建议的解决方案后设计器代码的样子..

Dim ValidationItem1 As Testing_Project.validationItem = New Testing_Project.validationItem(Testing_Project.validationItem.validationTypes.MaxValue, "4")
Dim ValidationItem2 As Testing_Project.validationItem = New Testing_Project.validationItem(Testing_Project.validationItem.validationTypes.MinLength, "5")

Me.Textbox1.Validations.Add(ValidationItem1)
Me.Textbox1.Validations.Add(ValidationItem2)

我从设计器中添加了一些项目,并尝试在运行时检索它们,但所有键都设置为 0,值设置为 Nothing。我需要通过设计器添加的项目的确切列表也可用,我怎样才能使它工作,以便通过设计器添加的实际值也存在于运行时。

【问题讨论】:

  • 旁注:如果它只包含一个文本框,它可能不需要是一个用户控件。你可以Inherit TextBox 并添加你的东西。
  • @DanielCook 我有这个设置并链接到用户控件中的一个属性。我正在通过设计器添加项目。
  • @DanielCook 我从表单设计器文件中提取了这里是如何添加项目的.. Me.Textbox1.Validations.Add(CType(resources.GetObject("Textbox1.Validation"), Testing_Project。验证项))
  • 注意:当设计师访问这样的资源时,这表明序列化 - 主要是您的类型转换器 - (还)不起作用。它也将很快崩溃。他们应该看起来像他们在答案中所做的那样。当它无法弄清楚要做什么和/或您的类型转换器没有帮助它将您的对象作为 Base64 字符串存储在资源中时......但它不能/不会长时间正确地从该字符串中进行 DESerialize。

标签: vb.net user-controls collectioneditor


【解决方案1】:

对 UC 属性的一些更改:

'Imports System.ComponentModel.DesignerSerializationVisibility
Imports System.ComponentModel

' Changed name to be able to tell these from regular ones
Public Class SuperText   
    Inherits System.Windows.Forms.TextBox
    Private _validation As New validationList

    ' I changed name to PLURAL because it is a collection
    <System.ComponentModel.DesignerSerializationVisibility(Content)>
    Public Property Validations As validationList
        Get
            ' just to be sure:
            If _validation Is Nothing Then
               _validation = New validationList
            End If

            Return _validation
        End Get
        Set(ByVal value As validationList)
            ' you do NOT want anyone to be able to change your collection!
            '_validation = value
        End Set
    End Property

    ' missing some serialization elements:
    ' use the right ShouldSerializeXXXX / ResetXXX names
    ' where XXX == your property name
    ' this also controls whether the property shows as BOLD when there are items
    Private Function ShouldSerializeValidations As Boolean
        Return _validation.Count > 0
    End Function

    Private Sub ResetValidations
         ' often you do nothing here
         _validation = New validationList
    End Sub

End Class

项目类缺少所有序列化支持,这些是实际序列化的项目:

' these should show as text in a drop down, lets use 
' better names (just a suggestion)
' Moved out of Item class to make references shorter
Public Enum validationTypes
    IsRequired
    IsInteger

   ' maybe IsValue  how is Numeric this different from
   ' Integer or Decimal
    Numeric        
    IsDecimal 
    MaxValue 
    MinValue 
    MinLength 
    Email 
End Enum

 <TypeConverter(GetType(ValidationItemConverter))>   ' might need
 <Serializable()> 
 Public Class validationItem

    Public Sub New()
        '//Empty constructor is needed for serialization
        ' actually SIMPLE ctor is needed for the Collection Editor
        ' we dont want Nothings flying about:
        Key = validationTypes.IsRequired
        Value = "False"   ' whatever it should be
    End Sub

    ' we will probably need this for a TypeConverter
    Public Sub New(ByVal k As validationTypes, ByVal v As String)
        Key = k
        Value = v
    End Sub

    ' TODO:
    ' Add a NAME property (avoid MyThing + SuperText in Editor ListBox)
    ' or Override TOSTRING to return Key.ToString to 
    ' the method(s) to apply the rules is missing too obviously

    ' recent VS versions allow Auto Implemented props so no need for 
    ' a backing field...makes for less SO code too...

    ' we need to tell VS how to serialize this:
    <DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)>
    Public Property Value As String

    <DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)>
    Public Property Key As validationTypes

End Class

试试这个......它可能不会工作,但它可能会。使用 DesignerSerializationVisibility.Visible&gt; 可能会导致 Item 值被序列化。如果没有,(即使有)您将需要TypeConverter

所以你知道,这就是我们正在谈论的。在表单的 Sub New 中,深入到 InitializeComponent。添加到集合中的验证项的代码如下所示:

Dim FooBar4 As Plutonix.SomeClass.FooBar = 
                New Plutonix.MyThing.FooBar("NewFoo", "sdfsdf")
...

Me.MyThing.FooList.Add(FooBar4)
Me.MyThing.FooList.Add(FooBar5)
Me.MyThing.FooList.Add(FooBar6)

VS 需要帮助创建该代码,因为它不知道如何创建 FooBarValidationItem 以添加到集合中。

这也是检查您距离确定序列化要求的距离的好方法。


您可能需要一个用于 VS 的 TypeConverter 来调用来为设计器代码创建对象。我们需要返回一个InstanceDescriptor。这是与您的收藏类似的东西的代码,您应该能够适应:

Imports System.ComponentModel.Design.Serialization

Friend Class RowFilterConverter
    Inherits TypeConverter

    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
            ' convert value (the current instance) to Type
            Dim rf As RowFilter = CType(value, RowFilter)

            ' prepare a constructor info
            Dim ctor As Reflection.ConstructorInfo

            ' the ctor I want takes a string, Integer, enum, String
            ' validation item would be just the validationTypes enum, String
            ctor = GetType(RowFilter).GetConstructor(New Type() _
                                     {GetType(String),
                                      GetType(Integer),
                                      GetType(ExcludeOperators),
                                      GetType(String)})

            ' return Instance Descriptor built from ctor info 
            ' and an array of the current
            '   values for the ctor params
            Return New InstanceDescriptor(ctor,
                        New Object() {rf.Name, rf.FieldIndex, 
                                      rf.Operation, rf.Target}, True)

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

    End Function

End Class
  • &lt;TypeConverter(GetType(ValidationItemConverter))&gt; 添加到您的ValidationItem 类中
  • 将 DesignerVisibility 值更改为 .Hidden,因为我们是通过构造函数完成的
  • 强烈建议您在控件开始成熟后立即将其移至控件库 (DLL),以免对其进行意外更改。如果您最终在 Lib 中得到其他不密切相关的东西,请使用 NameSpace 包装器。

有了TypeConverter 和其他东西,你应该很高兴。您将需要经常构建和清理。 VS 运行此代码,因此您要确保它没有使用过时的代码,否则您最终会追逐鬼魂。


这或多或少的工作方式是,在通过集合编辑器添加一些项目后,VS 将表单标记为脏,重写设计器文件(InitializeComponent 中的代码)然后重新加载表单(这就是它可能闪烁的原因)。

这反过来又会调用你的类Add 过滤掉骗子的方法。我认为编辑器在打开时使用集合的临时副本,因此如果您可以取消,它只会返回原始版本。因此,在编辑器中,当您单击添加按钮时,您的 Add 代码不会运行。这就是编辑器中没有过滤掉骗子的原因。

当您关闭编辑器并使用新的设计器代码重新构建表单时,您的 Add 确实会运行,但这意味着您将仅保留使用 IsFoo 的第一个实例,而其他实例将被丢弃。解决这个问题的方法是使用自定义集合编辑器来轮询集合类以查看是否可以向集合添加新的 IsFoo 类型。

您必须决定是否值得使用自定义集合编辑器,或者仅保存验证规则的第一个实例就足够了。

【讨论】:

  • 我想我将只保存验证规则的第一个实例。由于这已经变得比我目前所能处理的要复杂得多.. :) 感谢您抽出时间提供描述性的答案。将尝试并让您知道...
  • 我正在查看您的答案并看到属性 Validations 上的 set 方法丢失了。我也想在运行时将项目添加到此集合中,它是否会因没有设置器而受到影响方法。
  • 这就是 Add 方法的用途...mySuperText.Validations.Add(myValidationItem)想要的是这样做:mySuperText.Validations = Nothing 并删除或更改整个集合 -当它是 CollectionBase 时,他们可以用色情链接填充它,这也是我的 List(of T) 不好 - 你不能阻止它,因为你暴露了收集容器
  • 并且 Private Property ShouldSerializeValidations As Boolean 这行应该是 Private Function ShouldSerializeValidations As Boolean 对.. 因为你有 End Function ..
  • 是的,抱歉,这是一个功能 - 拼写错误是免费的。 SO答案框没有强大的语法检查器:)
猜你喜欢
  • 1970-01-01
  • 2020-07-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多