【问题标题】:Inherited ComboBox for Color support populates items multiple timesInherited ComboBox for Color 支持多次填充项目
【发布时间】:2012-06-27 22:59:54
【问题描述】:

以下是继承的 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

【问题讨论】:

  • 我已尝试按原样使用您修改后的 ComboBoxExColors 类,但看不到任何重复项。可能是 Designer.vb 的旧代码(其中明确添加了项目)仍然存在。我认为重复项目除此之外没有其他原因。要删除旧代码,请从设计器表面删除控件,重新构建解决方案,然后再次将 ComboBoxExColors 控件放在表面上。要进行测试,您还可以添加一个新的虚拟测试表单并在其上放置 ComboBoxExColors。
  • 每次对代码进行调整时,我都会从设计器中移除控件。我运行了一次应用程序,它很好,我查看了设计器集合并且项目在那里。一旦我再次运行该应用程序,这些项目就会列出两次。我不明白为什么设计器要存储在运行时添加的值。如果我在添加之前将其设置为清除项目,则它可以工作。但是对于我没有正确实现的代码,或者它可能是一个错误,这不是一个优雅的解决方案。
  • 您是否尝试过使用空白的虚拟测试表?这个问题是否也会重复?在我的最后,你的新代码不会发生这种情况,而当你使用构造函数时我可以重现它。

标签: .net vb.net winforms combobox visual-studio-2008-sp1


【解决方案1】:

问题是 PopulateComboBox 是从构造函数中调用的。

当您将组合框放在设计器表面时,设计器会在内部调用其构造函数以获取其属性(包括 Item 属性)的默认值。然后,后面的代码调用构造函数,然后显式指定设计时属性(在您的情况下,这似乎只是“默认”值)。因此重复的项目。

初始化自定义控件的正确方法是实现ISupportInitialize 接口。

在设计器的代码应用了所有设计时属性后,EndInit 将被调用一次(如果您没有使用设计器,那么调用它是您的责任)。

所以经验法则是

  1. 对于默认值,在构造函数中指定
  2. 要“初始化”,请使用 ISupportInitialize。

例如,除了从中调用 PopulateComboBox 之外,您还可以使用它来强制 DrawMode 属性为 OwnerDrawFixed,因为这对于您继承的控件至关重要,并且您不希望让控件的用户在设计时指定任何其他内容时间(虽然这不会完全阻止不同值的设计时间“规范”,但不管在运行时,您总是会强制使用正确的值。)

注意:

  1. 实现此接口后,您可能需要重新构建项目,然后在设计器界面上再次“拖放”继承的控件。您可以检查自动创建的设计器代码,以验证 EndInit 确实被调用了。
  2. 同样如前所述,设计人员使用 ISupportInitialize。如果您不使用设计器,则调用其方法是您的责任。

【讨论】:

  • 我在继承的控件中实现了ISupportInitialize,并从EndInit()调用PopulateComboBox。谢谢。
【解决方案2】:

除非您打算稍后动态更改值,否则它应该在 Sub New 中。

另外,我不知道您为什么需要清除阵列。 GC 会处理它。

【讨论】:

  • 我已经更正了上面的代码以更好地演示这个问题,因为它仍然存在。请再次查看。
【解决方案3】:

在调查您的问题时,我最初认为使用 DesignMode 属性会阻止在将控件添加到表单时创建 ItemArray...但它不起作用。

然后我将另一个 Visual Studio 实例附加到项目中,并注意到 DesignMode 一直设置为 false。我无法找到另一个独特的属性,以防止您的控件在将 ItemArray 添加到表单时创建它(这是导致第一次加载数据的原因)。

您正在尝试做的事情是独一无二的,因为您将数据源构建到您的控件中并在每次创建它时运行它,而普通的 ComboBox 只会从属性或附加的数据源加载到数组中。

此时我唯一的建议是将您的 PopulateComboBox 方法从控件的构造函数中取出,并在父表单的构造函数中调用它,或者动态创建它并将其添加到您的表单中。

Public Class Form1
    Public Sub New()
        InitializeComponent()
        ComboBoxExColors1.PopulateComboBox()
    End Sub
End Class

【讨论】:

  • 我之前用Return System.Diagnostics.Process.GetCurrentProcess.ProcessName.EndsWith(".vshost") 代替了 DesignMode。此外,Return Not System.Diagnostics.Process.GetCurrentProcess.ProcessName.EndsWith(".exe") 也应该可以正常工作。感谢您的回答。
猜你喜欢
  • 1970-01-01
  • 2010-10-26
  • 1970-01-01
  • 2016-01-20
  • 1970-01-01
  • 2014-12-06
  • 2016-03-18
  • 1970-01-01
  • 2014-05-14
相关资源
最近更新 更多