On a recent project, one of my developers was trying to extend the combobox in a winforms project. We wanted to reuse the same combobox in several places.
The combobox would always have the same objects bound to it, and we wanted a few functions extra functions on the combobox that would centralize some functionality.
So we inherited from combobox, and in the constructor of our class we created the 5 objects that we need in the dropdown and we added them to the combobox items collection.
So far so good.
But we found that when we made a change in the designer for a form that uses this combobox, the designer put stuff in the designer.vb file. Lines that were trying to add items to our combobox.
It used the .items.AddRange(…) function and tried to add 1 item for every item that we add in the contructor.
Basically it was looking like the designer instantiated the control, and then was trying to serialize the items in the combobox when we would change anything on the form.
This would eventually cause the designer to blow up, as well as a similar error when we tried to run the compiled code.
The solution was elusive and quite a pain.
Some credit needs to go to Andre for his post.
Basically we needed a way to tell in our code if the control was being hosted in the VS designer. If it was, then we skipped the part where we populated this dropdown.
So first thing we did was create 2 functions to figure out where the control is hosted:
Private Function IsDesignerHosted() As Boolean Return Me.IsControlDesignerHosted(Me) End Function Private Function IsControlDesignerHosted(ByVal ctrl As Control) As Boolean If ctrl IsNot Nothing Then If ctrl.Site IsNot Nothing Then If ctrl.Site.DesignMode Then Return True Else Return IsControlDesignerHosted(ctrl.Parent) End If Else Return IsControlDesignerHosted(ctrl.Parent) End If Else Return False End If End Function
Then, because it turns out that testing the DesignMode is useless when you are doing the testing from the constructor, so I had to move the databinding into it’s own function along with a instance variable to make sure we only do this one time.
Private cbInit As Boolean = False Private Sub MyControl_VisibleChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.VisibleChanged If Not cbInit Then cbInit = True If Not Me.IsDesignerHosted Then '*** add items here End If End If End Sub
There it is!