下面是继承的ComboBox的代码。问题是ComboBox被多次填充(PopulateComboBox()
)。
编辑:我接受了 Amit Mittal 的建议(在下面找到他的答案)并实施了ISupportInitialize
。现在PopulateComboBox()
仅在运行时调用,就像它应该的那样。
通过此实现,项目应在运行时填充,并在退出时销毁。但是,设计者本身在创建运行时创建这些值,而不是在运行时销毁。
是否有优雅的解决方案来实现此代码?
Public Class ComboBoxExColors
Inherits ComboBox
Implements ISupportInitialize
Public Sub New()
MyBase.New()
Me.Size = New Size(146, 23)
Me.DropDownStyle = ComboBoxStyle.DropDownList
Me.MaxDropDownItems = 16
End Sub
Public Sub BeginInit() Implements System.ComponentModel.ISupportInitialize.BeginInit
' Do nothing?
End Sub
Public Sub EndInit() Implements System.ComponentModel.ISupportInitialize.EndInit
Me.DrawMode = DrawMode.OwnerDrawVariable ' fixed or variable?
Me.PopulateComboBox()
End Sub
Public Sub PopulateComboBox()
'Me.Items.Clear() ' rather than forcing items to be cleared, is there a more elegant solution to the implementation of this code, rather than forcing an item clear that shouldn't exist to begin with?
Me.Items.Add("Default")
Me.Items.Add("Custom")
Dim KnownColors() As String = System.Enum.GetNames(GetType(System.Drawing.KnownColor)) ' get all colors
For Each c As String In KnownColors ' add non system colors
If Not Color.FromName(c).IsSystemColor Then
Me.Items.Add(c)
End If
Next c
End Sub
Protected Overrides Sub OnDrawItem(ByVal e As DrawItemEventArgs)
' this draws each item onto the control
If e.Index > -1 Then
Dim item As String = Me.Items(e.Index).ToString
e.DrawBackground()
e.Graphics.DrawString(item, e.Font, SystemBrushes.WindowText, e.Bounds.X, e.Bounds.Y)
e.DrawFocusRectangle()
End If
End Sub
End Class
答案 0 :(得分:4)
问题是从构造函数调用PopulateComboBox。
当您在设计器表面设计器上放置组合框时,会在内部调用其构造函数以获取其属性的默认值(包括Item属性)。然后,后面的代码调用构造函数,然后显式指定设计时属性(在您的情况下似乎只是'默认'值)。因此重复了项目。
初始化自定义控件的正确方法是实现ISupportInitialize接口。
在设计师的代码应用了所有设计时属性之后,将会调用一次EndInit(如果您没有使用设计器,那么您有责任调用它)。
所以经验法则是
例如,除了从中调用PopulateComboBox之外,您还可以使用它将DrawMode属性强制为OwnerDrawFixed,因为这对于您继承的控件至关重要,并且您不希望让控件的用户在设计中指定任何其他内容。时间(虽然这不会完全阻止设计时间'规范'的不同值,但无论在运行时如何,您总是会强制使用正确的值。)
注意:
答案 1 :(得分:0)
除非您计划稍后动态更改值,否则它应该在Sub New中。
另外,我不知道你为什么需要清除数组。 GC会处理它。
答案 2 :(得分:0)
在查看您的问题时,我原本以为使用DesignMode属性会阻止在将控件添加到表单时创建ItemArray ......但它不起作用。
然后我将另一个Visual Studio实例附加到项目中,并注意到DesignMode
一直设置为false。我无法找到另一个独特的属性,可以让你的控件在添加到表单时不会创建ItemArray(这是导致第一次加载数据的原因)。
您尝试做的事情是独一无二的,因为您正在将数据源构建到Control中并在每次创建时运行它,而普通的ComboBox只是从属性或附加的数据源加载到数组中。
我目前唯一的建议是将您的PopulateComboBox
方法从Control的构造函数中取出,然后在父Form的构造函数中调用它,或者动态创建它并将其添加到您的表单中。
即。
Public Class Form1
Public Sub New()
InitializeComponent()
ComboBoxExColors1.PopulateComboBox()
End Sub
End Class