.net - How to properly implement/inherit a ComboBox.ObjectCollection class for design-time usage? -
scenario
i subclassed combobox
class design kind of combobox control on can supply custom type (myitem
) combobox.items collection...
this subclassed combobox class:
<designercategory("usercontrol")> public class mycombobox : inherits combobox <editor(gettype(collectioneditor), gettype(uitypeeditor))> <designerserializationvisibility(designerserializationvisibility.content)> public shadows readonly property items myitemcollection <debuggerstepthrough> public sub new() mybase.drawmode = drawmode.ownerdrawfixed me.items = new myitemcollection(owner:=me) end sub protected overrides sub ondrawitem(byval e drawitemeventargs) e.drawbackground() e.drawfocusrectangle() ' check if item items collection. if (e.index < 0) ' not item, draw text. using brush new solidbrush(e.forecolor) e.graphics.drawstring(me.text, e.font, brush, e.bounds.left, e.bounds.top) end using else ' item draw. dim item myitem = me.items(e.index) using brush new solidbrush(e.forecolor) e.graphics.drawstring(item.text, e.font, brush, e.bounds.left, e.bounds.top) end using end if mybase.ondrawitem(e) end sub end class
this subclassed combobox.objectcollection
class:
<listbindable(false)> <defaultmember("item")> public class myitemcollection : inherits objectcollection sub new(byval owner mycombobox) mybase.new(owner) end sub <browsable(false)> <designerserializationvisibility(designerserializationvisibility.hidden)> default public overloads property item(byval index integer) myitem return directcast(mybase.item(index), myitem) end set(byval value myitem) mybase.item(index) = value end set end property ' original property: ' '<browsable(false)> '<designerserializationvisibility(designerserializationvisibility.hidden)> 'default public overrides property item(byval index integer) object ' ' return mybase.item(index) ' end ' set(value object) ' mybase.item(index) = value ' end set 'end property end class
and custom type myitem
use items collection of control:
public notinheritable class myitem public property text string public sub new() me.new(string.empty) end sub public sub new(byval text string) me.text = text end sub end class
all works fine @ execution time, can add items , works expected, problem won't work @ design time...
problem
when try add item @ design time this:
...at first sight seems works, because can add item.
and record seems auto-generated visual studio in form's dsigner class (form1.designer.vb):
private sub initializecomponent() me.mycombobox1 = new mycombobox() dim myitem1 myitem = new myitem() myitem1.text = "test" me.mycombobox1.items.addrange(new object() {myitem1}) ' ... end sub
even more, if try determine @ execution time current amount of items inside collection calling items.count
property, gives me expected value:
public class form1 : inherits form sub form1_shown(sender object, e eventargs) handles mybase.shown messagebox.show(string.format("there '{0}' items in collection.", mycombobox1.items.count)) end sub end class
...however, of matters, because when launch application don't see item(s) added @ design time, mean items added @ design time not drawn in control @ execution time.
question
what i'm missing do?. how can fix that?.
please note not drawing problem, because items add through items.add()
, items.addrange()
method @ execution time added , drawn.
i think maybe sort of issue content synchronization...
i don't know happening, because through object inspector of visual studio ensured specify attribute classes classes, methods , properties, same assigned default combobox.items
property , combobox.objectcollection
class , combobox.objectcollection.item
member.
here example of technique mentioned in comments. highly reliant of using reflection set field in combobox class executing methods in class. such, subject breaking if ms ever modifies these items.
edit 2: corrected code
imports system.componentmodel imports system.componentmodel.design imports system.drawing.design imports system.reflection <designercategory("usercontrol")> public class mycombobox : inherits combobox private fiitemscollection fieldinfo private picmitem propertyinfo private minativeclear methodinfo private miobjectcollectionaddrangeinternal methodinfo private _items myitemcollection <editor(gettype(collectioneditor), gettype(uitypeeditor))> <designerserializationvisibility(designerserializationvisibility.content)> public shadows readonly property items myitemcollection return me._items end end property <debuggerstepthrough> public sub new() mybase.new() mybase.drawmode = drawmode.ownerdrawfixed me.fiitemscollection = gettype(combobox).getfield("itemscollection", bindingflags.instance or bindingflags.nonpublic) me._items = new myitemcollection(me) fiitemscollection.setvalue(me, me._items) me.picmitem = gettype(currencymanager).getproperty("item", bindingflags.instance or bindingflags.nonpublic) me.minativeclear = gettype(combobox).getmethod("nativeclear", bindingflags.instance or bindingflags.nonpublic) me.miobjectcollectionaddrangeinternal = gettype(objectcollection).getmethod("addrangeinternal", bindingflags.instance or bindingflags.nonpublic) end sub protected overrides sub refreshitems() dim selectedindex integer = me.selectedindex dim itemscollection myitemcollection = me._items me._items = nothing dim destination object() = nothing if ((not mybase.datamanager nothing) andalso (mybase.datamanager.count <> -1)) destination = new object(mybase.datamanager.count - 1) {} dim args(0 0) object int32 = 0 destination.length - 1 args(0) = destination(i) = picmitem.getvalue(mybase.datamanager, args) next elseif (not itemscollection nothing) destination = new object(itemscollection.count - 1) {} itemscollection.copyto(destination, 0) end if me.beginupdate() try if mybase.ishandlecreated me.minativeclear.invoke(me, nothing) end if if (not destination nothing) me._items = new myitemcollection(me) me.miobjectcollectionaddrangeinternal.invoke(me._items, new object() {destination}) me.fiitemscollection.setvalue(me, me._items) end if if (not mybase.datamanager nothing) me.selectedindex = mybase.datamanager.position else me.selectedindex = selectedindex end if me.endupdate() end try end sub protected overrides sub ondrawitem(byval e drawitemeventargs) e.drawbackground() e.drawfocusrectangle() ' check if item items collection. if (e.index < 0) ' not item, draw text. using brush new solidbrush(e.forecolor) e.graphics.drawstring(me.text, e.font, brush, e.bounds.left, e.bounds.top) end using else ' item draw. dim item myitem = me.items(e.index) using brush new solidbrush(e.forecolor) e.graphics.drawstring(item.text, e.font, brush, e.bounds.left, e.bounds.top) end using end if mybase.ondrawitem(e) end sub end class
Comments
Post a Comment