Serializing a Collection and Iextenderprovider

scali

Newcomer
Joined
May 10, 2005
Messages
4
Hello all,

I need help serializing a collection that is a property coming from the Iextenderprovider. The canextend is set to textboxes.

I have it working when adding/removing components to the collection when the parent component(the extender) calls the collection editor. However, when I try to add a collection through Iextenderprovider with the set/get methods I am able to call the collection editor and add a sub component but when I recall the collection editor the components that I added are no longer there.

I've searched for a few days trying to located a single instance in ether c# or vb.net where a collection is utilized in this way but havent had any luck.

I'd post the code but its just a bit to big after editing it down twice. If there is a section that I need to post please let me know.
 
Class 1

**Note Heavily modified into a component from the code posted by Divil's Rich Design Time Control.
Visual Basic:
Option Strict On
Option Explicit On 
Imports System.Data.OleDb
Imports System.Data.SqlClient
Imports System.ComponentModel
Imports System.ComponentModel.Design
Imports System.Windows.Forms.Design

<Designer("CollectionControlDesigner"), _
ProvideProperty("FieldValue", GetType(Control)), _
ProvideProperty("Clm", GetType(Control))> _
Public Class DataExtender
    Inherits System.ComponentModel.Component
    Implements IExtenderProvider
    Private _Columns As DataExtenderCollection

#Region " Windows Form Designer generated code "

    Public Sub New()
        MyBase.New()

        'This call is required by the Windows Form Designer.
        InitializeComponent()

        'Add any initialization after the InitializeComponent() call
        _Columns = New DataExtenderCollection(Me)
    End Sub

    'UserControl overrides dispose to clean up the component list.
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer

    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer.  
    'Do not modify it using the code editor.
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        components = New System.ComponentModel.Container
    End Sub

#End Region

#Region "Extender/Hashtable "
    Public Function CanExtend(ByVal extendee As Object) As Boolean _
          Implements IExtenderProvider.CanExtend

        If TypeOf extendee Is TextBox Then
            Return True
        Else
            Return False
        End If
    End Function

    ' this hashtable holds property values for individual controls
    Public htProvidedProperties As New Hashtable

    Public Function GetAddControl(ByVal ctrl As Control) As DataExtenderProperties
        If htProvidedProperties.Contains(ctrl) Then
            Return DirectCast(htProvidedProperties(ctrl), DataExtenderProperties)
        Else
            ' add an element to the hashtable
            Dim ProvidedProperties As New DataExtenderProperties
            htProvidedProperties.Add(ctrl, ProvidedProperties)

            Return ProvidedProperties
        End If
    End Function
#End Region ' Extender/Hastable

    'working content
    <Browsable(True), DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> _
    Public ReadOnly Property Columns() As DataExtenderCollection
        Get
            Return _Columns
        End Get
    End Property

#Region " Get/Set "
    'These need to be excatly the same as the provide properties
    Public Class DataExtenderProperties
        Public FieldValue As String = String.Empty
        Public Clm As DataExtenderCollection
        Public List As ListBox
    End Class

    Public Sub SetList(ByVal ctrl As Control, ByVal Value As ListBox)
        Me.GetAddControl(ctrl).List = Value
    End Sub

    Public Function GetList(ByVal ctrl As Control) As ListBox
        If htProvidedProperties.Contains(ctrl) Then
            Return DirectCast(Me.htProvidedProperties(ctrl), DataExtenderProperties).List
        Else
            Return Nothing
        End If
    End Function

    Public Sub SetClm(ByVal ctrl As Control, ByVal Value As DataExtenderCollection)
        If htProvidedProperties.Contains(ctrl) Then
            Me.GetAddControl(ctrl).Clm = Value
        End If
    End Sub

    Public Function GetClm(ByVal ctrl As Control) As DataExtenderCollection
        If htProvidedProperties.Contains(ctrl) Then
            Return DirectCast(Me.htProvidedProperties(ctrl), DataExtenderProperties).Clm
        End If
    End Function

    Function GetFieldValue(ByVal ctrl As Control) As String
        If htProvidedProperties.Contains(ctrl) Then
            Return DirectCast(Me.htProvidedProperties(ctrl), DataExtenderProperties).FieldValue
        Else
            Return String.Empty
        End If
    End Function

    Sub SetFieldValue(ByVal ctrl As Control, ByVal value As String)
        If value = Nothing Then value = String.Empty
        Me.GetAddControl(ctrl).FieldValue = value
    End Sub

#End Region 'Individual Control Extention
End Class

Friend Class CollectionControlDesigner
    Inherits ControlDesigner

    Private MyControl As DataExtender

    Public Overrides Sub Initialize(ByVal component As System.ComponentModel.IComponent)
        MyBase.Initialize(component)

        'Record instance of control we're designing
        MyControl = DirectCast(component, DataExtender)

        'Hook up events
        Dim s As ISelectionService = DirectCast(GetService(GetType(ISelectionService)), ISelectionService)
        Dim c As IComponentChangeService = DirectCast(GetService(GetType(IComponentChangeService)), IComponentChangeService)
        AddHandler c.ComponentRemoving, AddressOf OnComponentRemoving
    End Sub

    Private Sub OnComponentRemoving(ByVal sender As Object, ByVal e As ComponentEventArgs)
        Dim c As IComponentChangeService = DirectCast(GetService(GetType(IComponentChangeService)), IComponentChangeService)
        Dim button As DataExtenderColumns
        Dim h As IDesignerHost = DirectCast(GetService(GetType(IDesignerHost)), IDesignerHost)
        Dim i As Integer

        'If the user is removing a button
        If TypeOf e.Component Is DataExtenderColumns Then
            button = DirectCast(e.Component, DataExtenderColumns)
            If MyControl.Columns.Contains(button) Then
                c.OnComponentChanging(MyControl, Nothing)
                MyControl.Columns.Remove(button)
                c.OnComponentChanged(MyControl, Nothing, Nothing, Nothing)
                Return
            End If
        End If

        'If the user is removing the control itself
        If e.Component Is MyControl Then
            For i = MyControl.Columns.Count - 1 To 0 Step -1
                button = MyControl.Columns(i)
                c.OnComponentChanging(MyControl, Nothing)
                MyControl.Columns.Remove(button)
                h.DestroyComponent(button)
                c.OnComponentChanged(MyControl, Nothing, Nothing, Nothing)
            Next
        End If
    End Sub

    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        Dim s As ISelectionService = DirectCast(GetService(GetType(ISelectionService)), ISelectionService)
        Dim c As IComponentChangeService = DirectCast(GetService(GetType(IComponentChangeService)), IComponentChangeService)

        'Unhook events
        RemoveHandler c.ComponentRemoving, AddressOf OnComponentRemoving

        MyBase.Dispose(disposing)
    End Sub

    Public Overrides ReadOnly Property AssociatedComponents() As System.Collections.ICollection
        Get
            Return MyControl.Columns
        End Get
    End Property

    Private Sub OnAddButton(ByVal sender As Object, ByVal e As EventArgs)
        Dim button As DataExtenderColumns
        Dim h As IDesignerHost = DirectCast(GetService(GetType(IDesignerHost)), IDesignerHost)
        Dim dt As DesignerTransaction
        Dim c As IComponentChangeService = DirectCast(getservice(GetType(IComponentChangeService)), IComponentChangeService)

        'Add a new button to the collection
        dt = h.CreateTransaction("Add Button")
        button = DirectCast(h.CreateComponent(GetType(DataExtenderColumns)), DataExtenderColumns)
        c.OnComponentChanging(MyControl, Nothing)
        MyControl.Columns.Add(button)
        c.OnComponentChanged(MyControl, Nothing, Nothing, Nothing)
        dt.Commit()
    End Sub
End Class
 
Last edited by a moderator:
Class 2

*Note heavily based upon Divi's posted Rich Design Time Controls
Visual Basic:
Option Strict On
Option Explicit On 
Imports System.ComponentModel
Imports System.ComponentModel.Design.Serialization

<TypeConverter(GetType(DataExtenderConverter)), DesignTimeVisible(True), ToolboxItem(False)> _
Public Class DataExtenderColumns
    Inherits Component
    Private _ColumnName As String

    Friend Control As DataExtender = Nothing

    Public Property ColumnName() As String
        Get
            Return Me._ColumnName
        End Get
        Set(ByVal Value As String)

            Me._ColumnName = Value
        End Set
    End Property
End Class

Friend Class DataExtenderConverter
    Inherits TypeConverter

    Public Overloads Overrides Function CanConvertTo(ByVal context As ITypeDescriptorContext, ByVal destType As Type) As Boolean
        If destType Is GetType(InstanceDescriptor) Then
            Return True
        End If

        Return MyBase.CanConvertTo(context, destType)
    End Function

    Public Overloads Overrides Function ConvertTo(ByVal context As ITypeDescriptorContext, ByVal culture As System.Globalization.CultureInfo, ByVal value As Object, ByVal destType As Type) As Object
        If destType Is GetType(InstanceDescriptor) Then
            Dim ci As System.Reflection.ConstructorInfo = GetType(DataExtenderColumns).GetConstructor(System.Type.EmptyTypes)

            Return New InstanceDescriptor(ci, Nothing, False)
        End If

        Return MyBase.ConvertTo(context, culture, value, destType)
    End Function
End Class

Public Class DataExtenderCollection
    Inherits CollectionBase

    Private Control As DataExtender

    Friend Sub New(ByVal Control As DataExtender)
        Me.Control = Control
    End Sub

    Default Public ReadOnly Property Item(ByVal Index As Integer) As DataExtenderColumns
        Get
            Return DirectCast(List(Index), DataExtenderColumns)
        End Get
    End Property

    Public Function Contains(ByVal DC As DataExtenderColumns) As Boolean
        Return List.Contains(DC)
    End Function

    Public Function Add(ByVal DC As DataExtenderColumns) As Integer
        Dim i As Integer

        i = List.Add(DC)
        DC.Control = Control

        Return i
    End Function

    Public Sub Remove(ByVal DC As DataExtenderColumns)
        List.Remove(DC)
        DC.Control = Nothing
    End Sub
End Class
 
Last edited by a moderator:
Maybe I was to vague.

I'd like to extend to a textbox the ability to hold a collection of values. Is this possible.
 
Back
Top