VB.Net items added via the designer not reflected on code

淺唱寂寞╮ 提交于 2019-12-13 18:44:46

问题


I have a usercontrol which exposes a property of a custom collection.

Here is the code used in the usercontrol.

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

Here is the collection class that this property uses.

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

Here is the list of items that the collection class use

<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

Here is what the designer code looks like after implementing the solution suggested by 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)

I added a number of items to collection from the designer & I tried to retrieve them at runtime but all the keys are set to 0 and values are set to Nothing. I need the exact list of items added via the designer to be available as well, how can I make it work so that the actual values added via the designer exists at runtime as well.


回答1:


A few changes to the UC property:

'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

The item class is missing all the serialization support, these are the items that actually get serialized:

' 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

TRY this...it probably wont work, but it might. Using DesignerSerializationVisibility.Visible> might result in the Item values getting serialized. If not, (and even if it does) you will need a TypeConverter.

So you know, this is what we are talking about. In your Sub New for the form, drill into the InitializeComponent. The code for your validation items getting added to the collection will look like this:

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 needs help creating that code because it has no idea how to create a FooBar or ValidationItem to add to the collection.

This is also a good way to examine how close you are to nailing the serialization requirements.


You probably will need a TypeConverter for VS to invoke to create your objects for the designer code. We need to return an InstanceDescriptor. This is code for one from something which does something similar to your collection which you should be able to adapt:

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
  • Add <TypeConverter(GetType(ValidationItemConverter))> to your ValidationItem class
  • Change the DesignerVisibility value to .Hidden because we are doing them via the constructor
  • Strongly suggest you move the control to a Control Lib (DLL) as soon as it starts to reach maturity so that accidental changes to it are more difficult. use a NameSpace wrapper if you end up with other things in the Lib which are not closely related.

With a TypeConverter and the other stuff, you should be good to go. You will need to Build and Clean often. VS runs this code so you want to be sure that it is not using stale code or you end up chasing ghosts.


The way this more or less works is that after adding some items via the Collection Editor, VS marks the form as dirty, rewrites the designer file (the code in InitializeComponent) then reloads the form (thats why it might flicker).

This in turn calls your class Add method which filters out the dupes. I think the Editor uses a temp copy of the collection while open so if you can CANCEL, it just returns the original version. So in the Editor, your Add code doesn't run when you click the ADD button. This is why dupes arent filtered out in the editor.

You Add does run when you close the editor and the form is rebuilt with the new designer code, but that means you will be retaining only the first instance using IsFoo and the others discarded. The way around this is a custom collection editor to poll the collection class to see if it is okay to add a new IsFoo type to the collection.

You will have to decide if a Custom Collection Editor is worth it or just saving the first instance of a validation rule is good enough.



来源:https://stackoverflow.com/questions/24369553/vb-net-items-added-via-the-designer-not-reflected-on-code

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!