G
Guest
Hi,
I am strugling with the propertygrid and a listbox. I am using the
universaldropdowneditor from the codeproject (code below). However I am
populating the listbox via a datasource. The problem I am having is that when
I have a value in the propertygird and edit that, I want the listbox to have
the selectvalue equal to the value that is being edited. Just to make it
clearer:
PropgridVal = Germany
Datasource=
Belgium
France
Italie
Germany
Currently when I edit a value it defaults directly to Belgium, instead of
Germany
I do not understand, when I use listbox.selectedvalue="Germany" the
selectedvalue remains Nothing
please help
Thankks
David J
#Region " UniversalDropdownEditor class "
Public Class UniversalDropdownEditor
Inherits UITypeEditor
Private edSvc As IWindowsFormsEditorService
Private valMemb As ValueMemberAttribute
Public Overloads Overrides Function GetEditStyle(ByVal context As _
ITypeDescriptorContext) As UITypeEditorEditStyle
If Not context Is Nothing AndAlso Not context.Instance Is Nothing Then
Return UITypeEditorEditStyle.DropDown
End If
Return UITypeEditorEditStyle.None
End Function
<RefreshProperties(RefreshProperties.All)> _
Public Overloads Overrides Function EditValue( _
ByVal context As ITypeDescriptorContext, _
ByVal provider As System.IServiceProvider, _
ByVal value As [Object]) As [Object]
If context Is Nothing OrElse provider Is Nothing _
OrElse context.Instance Is Nothing Then
Return MyBase.EditValue(provider, value)
End If
' Dim att As SourceCollectionAttribute = _
' context.PropertyDescriptor.Attributes( _
' GetType(SourceCollectionAttribute))
'If att Is Nothing Then
' nothing we can do here
'Return MyBase.EditValue(provider, value)
'End If
Me.edSvc = provider.GetService(GetType(IWindowsFormsEditorService))
'If Me.edSvc Is Nothing Then
' nothing we can do here either
'Return MyBase.EditValue(provider, value)
'End If
'prepare the listbox
Dim lst As New ListBox()
Me.PrepareListBox(lst, context)
If Me.valMemb Is Nothing Then
lst.SelectedItem = value
Else
Me.valMemb.SelectByValue(lst, value)
End If
Me.switchloaded = False
Me.edSvc.DropDownControl(lst)
Me.switchloaded = True
' we're back
If lst.SelectedItem Is Nothing Then
value = Nothing
Else
value = lst.Text
'Else
' value = Me.valMemb.GetValue(lst)
End If
Return value
End Function
Private Sub PrepareListBox(ByVal lst As ListBox, _
ByVal context As ITypeDescriptorContext)
Dim SysSetTypeAttr As PropertySysSetTypeAttribute =
context.PropertyDescriptor.Attributes(GetType(PropertySysSetTypeAttribute))
Dim syssetType As Short = SysSetTypeAttr.PropertySysSetTypeAttribute
lst.IntegralHeight = True ' resize to avoid partial items
Dim coll As DataTable =
funGetPropVal(context.PropertyDescriptor.Name, SysSetType)
If lst.ItemHeight > 0 Then
Dim adjHei As Integer = (coll.Rows.Count + 1) * lst.ItemHeight
If Not coll Is Nothing AndAlso _
lst.Height / lst.ItemHeight < coll.Rows.Count Then
' try to keep the listbox small but sufficient
If adjHei > 200 Then adjHei = 200
End If
lst.Height = adjHei
Else ' safeguard, although it shouldn't happen
lst.Height = lst.ItemHeight
End If
lst.Sorted = True ' present in alphabetical order
FillListBoxFromCollection(lst, coll)
Me.AssignValueMember(lst, context.PropertyDescriptor)
Me.AssignDisplayMember(lst, context.PropertyDescriptor)
' attach event handler
AddHandler lst.SelectedIndexChanged, AddressOf Me.handleSelection
AddHandler lst.DoubleClick, AddressOf Me.handledoubleclick
End Sub
Public Shared Sub FillListBoxFromCollection(ByVal lb As ListBox, ByVal
coll As DataTable)
Dim DataRowX As DataRow
' prevent flickers and slow downs by entering the mass update mode
lb.BeginUpdate()
lb.Items.Clear()
lb.MultiColumn = False
Dim intCount As Integer
lb.DataSource = coll
lb.Invalidate()
End Sub
Private Sub AssignValueMember(ByVal lc As ListControl, ByVal pd As
PropertyDescriptor)
Dim Attr As ValueMemberAttribute = New ValueMemberAttribute("Name")
Me.valMemb = Attr 'pd.Attributes(GetType(ValueMemberAttribute))
lc.ValueMember = Me.valMemb.ValuePropertyName
End Sub
Private Sub AssignDisplayMember(ByVal lc As ListControl, ByVal pd As
PropertyDescriptor)
Dim att As DisplayMemberAttribute = New DisplayMemberAttribute("Name")
If att Is Nothing Then Return
lc.DisplayMember = att.DisplayPropertyName
End Sub
Private Sub handleSelection(ByVal sender As Object, ByVal e As EventArgs)
If Me.edSvc Is Nothing Then Return
If Me.switchloaded = False Then Return
Me.edSvc.CloseDropDown()
End Sub
Private Sub handledoubleclick(ByVal sender As Object, ByVal e As
EventArgs)
If Me.edSvc Is Nothing Then Return
Me.edSvc.CloseDropDown()
End Sub
End Class
#End Region
#Region " Attributes "
#Region " Auxiliary attribute that fetches the specified source collection "
<Description("Service attribute to point to the source collection."), _
AttributeUsage(AttributeTargets.All)> _
Public Class SourceCollectionAttribute
Inherits Attribute
Private srcCollName As String
Public ReadOnly Property CollectionName() As String
Get
Return Me.srcCollName
End Get
End Property
Public ReadOnly Property Collection(ByVal instance As Object) As
ICollection
Get
Dim pdc As PropertyDescriptorCollection = _
TypeDescriptor.GetProperties(instance)
Dim pd As PropertyDescriptor
For Each pd In pdc
If pd.Name = Me.srcCollName Then
Return pd.GetValue(instance)
End If
Next
Return Nothing
End Get
End Property
Public Sub New(ByVal sourceCollectionPropertyName As String)
Me.srcCollName = sourceCollectionPropertyName
End Sub
End Class
#End Region
#Region " 'Value member' attribute "
<AttributeUsage(AttributeTargets.All)> _
Public Class ValueMemberAttribute
Inherits Attribute
Private valMemb As String
<Description("The name of the property used as value member by the
dynamic combo type editor.")> _
Public ReadOnly Property ValuePropertyName() As String
Get
Return Me.valMemb
End Get
End Property
Public Sub SelectByValue(ByVal lb As ListBox, ByVal val As Object)
lb.SelectedItem = Nothing
Dim item As Object
If Not val Is Nothing Then
For Each item In lb.Items
If Me.GetValue(item) = val Then
lb.SelectedItem = item
Exit Sub
End If
Next
End If
End Sub
Public Function GetValue(ByVal obj As Object) As Object
If Me.valMemb = String.Empty Then Return obj
' Dim pi As System.Reflection.PropertyInfo =
obj.GetType().GetProperty("Row")
Dim pi As String = obj.text
If pi Is Nothing Then Return obj
Return pi
End Function
Public Sub New(ByVal valueMemberPropertyName As String)
Me.valMemb = valueMemberPropertyName
End Sub
End Class
#End Region
#Region " 'Display member' attribute "
<AttributeUsage(AttributeTargets.All)> _
Public Class DisplayMemberAttribute
Inherits Attribute
Private dispMemb As String
<Description("The property displayed in the list control used by the
dynamic combo editor.")> _
Public ReadOnly Property DisplayPropertyName() As String
Get
Return Me.dispMemb
End Get
End Property
Public Sub New(ByVal displayMemberPropertyName As String)
Me.dispMemb = displayMemberPropertyName
End Sub
End Class
I am strugling with the propertygrid and a listbox. I am using the
universaldropdowneditor from the codeproject (code below). However I am
populating the listbox via a datasource. The problem I am having is that when
I have a value in the propertygird and edit that, I want the listbox to have
the selectvalue equal to the value that is being edited. Just to make it
clearer:
PropgridVal = Germany
Datasource=
Belgium
France
Italie
Germany
Currently when I edit a value it defaults directly to Belgium, instead of
Germany
I do not understand, when I use listbox.selectedvalue="Germany" the
selectedvalue remains Nothing
please help
Thankks
David J
#Region " UniversalDropdownEditor class "
Public Class UniversalDropdownEditor
Inherits UITypeEditor
Private edSvc As IWindowsFormsEditorService
Private valMemb As ValueMemberAttribute
Public Overloads Overrides Function GetEditStyle(ByVal context As _
ITypeDescriptorContext) As UITypeEditorEditStyle
If Not context Is Nothing AndAlso Not context.Instance Is Nothing Then
Return UITypeEditorEditStyle.DropDown
End If
Return UITypeEditorEditStyle.None
End Function
<RefreshProperties(RefreshProperties.All)> _
Public Overloads Overrides Function EditValue( _
ByVal context As ITypeDescriptorContext, _
ByVal provider As System.IServiceProvider, _
ByVal value As [Object]) As [Object]
If context Is Nothing OrElse provider Is Nothing _
OrElse context.Instance Is Nothing Then
Return MyBase.EditValue(provider, value)
End If
' Dim att As SourceCollectionAttribute = _
' context.PropertyDescriptor.Attributes( _
' GetType(SourceCollectionAttribute))
'If att Is Nothing Then
' nothing we can do here
'Return MyBase.EditValue(provider, value)
'End If
Me.edSvc = provider.GetService(GetType(IWindowsFormsEditorService))
'If Me.edSvc Is Nothing Then
' nothing we can do here either
'Return MyBase.EditValue(provider, value)
'End If
'prepare the listbox
Dim lst As New ListBox()
Me.PrepareListBox(lst, context)
If Me.valMemb Is Nothing Then
lst.SelectedItem = value
Else
Me.valMemb.SelectByValue(lst, value)
End If
Me.switchloaded = False
Me.edSvc.DropDownControl(lst)
Me.switchloaded = True
' we're back
If lst.SelectedItem Is Nothing Then
value = Nothing
Else
value = lst.Text
'Else
' value = Me.valMemb.GetValue(lst)
End If
Return value
End Function
Private Sub PrepareListBox(ByVal lst As ListBox, _
ByVal context As ITypeDescriptorContext)
Dim SysSetTypeAttr As PropertySysSetTypeAttribute =
context.PropertyDescriptor.Attributes(GetType(PropertySysSetTypeAttribute))
Dim syssetType As Short = SysSetTypeAttr.PropertySysSetTypeAttribute
lst.IntegralHeight = True ' resize to avoid partial items
Dim coll As DataTable =
funGetPropVal(context.PropertyDescriptor.Name, SysSetType)
If lst.ItemHeight > 0 Then
Dim adjHei As Integer = (coll.Rows.Count + 1) * lst.ItemHeight
If Not coll Is Nothing AndAlso _
lst.Height / lst.ItemHeight < coll.Rows.Count Then
' try to keep the listbox small but sufficient
If adjHei > 200 Then adjHei = 200
End If
lst.Height = adjHei
Else ' safeguard, although it shouldn't happen
lst.Height = lst.ItemHeight
End If
lst.Sorted = True ' present in alphabetical order
FillListBoxFromCollection(lst, coll)
Me.AssignValueMember(lst, context.PropertyDescriptor)
Me.AssignDisplayMember(lst, context.PropertyDescriptor)
' attach event handler
AddHandler lst.SelectedIndexChanged, AddressOf Me.handleSelection
AddHandler lst.DoubleClick, AddressOf Me.handledoubleclick
End Sub
Public Shared Sub FillListBoxFromCollection(ByVal lb As ListBox, ByVal
coll As DataTable)
Dim DataRowX As DataRow
' prevent flickers and slow downs by entering the mass update mode
lb.BeginUpdate()
lb.Items.Clear()
lb.MultiColumn = False
Dim intCount As Integer
lb.DataSource = coll
lb.Invalidate()
End Sub
Private Sub AssignValueMember(ByVal lc As ListControl, ByVal pd As
PropertyDescriptor)
Dim Attr As ValueMemberAttribute = New ValueMemberAttribute("Name")
Me.valMemb = Attr 'pd.Attributes(GetType(ValueMemberAttribute))
lc.ValueMember = Me.valMemb.ValuePropertyName
End Sub
Private Sub AssignDisplayMember(ByVal lc As ListControl, ByVal pd As
PropertyDescriptor)
Dim att As DisplayMemberAttribute = New DisplayMemberAttribute("Name")
If att Is Nothing Then Return
lc.DisplayMember = att.DisplayPropertyName
End Sub
Private Sub handleSelection(ByVal sender As Object, ByVal e As EventArgs)
If Me.edSvc Is Nothing Then Return
If Me.switchloaded = False Then Return
Me.edSvc.CloseDropDown()
End Sub
Private Sub handledoubleclick(ByVal sender As Object, ByVal e As
EventArgs)
If Me.edSvc Is Nothing Then Return
Me.edSvc.CloseDropDown()
End Sub
End Class
#End Region
#Region " Attributes "
#Region " Auxiliary attribute that fetches the specified source collection "
<Description("Service attribute to point to the source collection."), _
AttributeUsage(AttributeTargets.All)> _
Public Class SourceCollectionAttribute
Inherits Attribute
Private srcCollName As String
Public ReadOnly Property CollectionName() As String
Get
Return Me.srcCollName
End Get
End Property
Public ReadOnly Property Collection(ByVal instance As Object) As
ICollection
Get
Dim pdc As PropertyDescriptorCollection = _
TypeDescriptor.GetProperties(instance)
Dim pd As PropertyDescriptor
For Each pd In pdc
If pd.Name = Me.srcCollName Then
Return pd.GetValue(instance)
End If
Next
Return Nothing
End Get
End Property
Public Sub New(ByVal sourceCollectionPropertyName As String)
Me.srcCollName = sourceCollectionPropertyName
End Sub
End Class
#End Region
#Region " 'Value member' attribute "
<AttributeUsage(AttributeTargets.All)> _
Public Class ValueMemberAttribute
Inherits Attribute
Private valMemb As String
<Description("The name of the property used as value member by the
dynamic combo type editor.")> _
Public ReadOnly Property ValuePropertyName() As String
Get
Return Me.valMemb
End Get
End Property
Public Sub SelectByValue(ByVal lb As ListBox, ByVal val As Object)
lb.SelectedItem = Nothing
Dim item As Object
If Not val Is Nothing Then
For Each item In lb.Items
If Me.GetValue(item) = val Then
lb.SelectedItem = item
Exit Sub
End If
Next
End If
End Sub
Public Function GetValue(ByVal obj As Object) As Object
If Me.valMemb = String.Empty Then Return obj
' Dim pi As System.Reflection.PropertyInfo =
obj.GetType().GetProperty("Row")
Dim pi As String = obj.text
If pi Is Nothing Then Return obj
Return pi
End Function
Public Sub New(ByVal valueMemberPropertyName As String)
Me.valMemb = valueMemberPropertyName
End Sub
End Class
#End Region
#Region " 'Display member' attribute "
<AttributeUsage(AttributeTargets.All)> _
Public Class DisplayMemberAttribute
Inherits Attribute
Private dispMemb As String
<Description("The property displayed in the list control used by the
dynamic combo editor.")> _
Public ReadOnly Property DisplayPropertyName() As String
Get
Return Me.dispMemb
End Get
End Property
Public Sub New(ByVal displayMemberPropertyName As String)
Me.dispMemb = displayMemberPropertyName
End Sub
End Class