0

以下は、継承されたComboBoxのコードです。問題は、ComboBoxがPopulateComboBox()複数回入力されている()ことです。

編集:私はAmit Mittalのアドバイスを受け(以下で彼の答えを見つけてください)、実装しISupportInitializeました。NowPopulateComboBox()は、実行時にのみ呼び出されます。

この実装では、アイテムは実行時に入力され、終了時に破棄される必要があります。ただし、デザイナ自体は、実行時に作成されたときにこれらの値を格納し、実行後に破棄することはありません。

このコードの実装に対する洗練されたソリューションはありますか?

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
4

3 に答える 3

4

問題は、PopulateComboBoxがコンストラクターから呼び出されていることです。

コンボボックスをデザイナサーフェスにドロップすると、デザイナはそのコンストラクタを内部的に呼び出して、そのプロパティ(Itemプロパティを含む)のデフォルト値を取得します。次に、背後のコードがコンストラクターを呼び出し、その後、設計時のプロパティも明示的に指定します(この場合は「デフォルト」値のみのようです)。したがって、アイテムの複製。

カスタムコントロールを初期化する適切な方法は、ISupportInitializeインターフェイスを実装することです。

EndInitは、デザイナーのコードがすべてのデザイン時プロパティを適用した後に1回だけ呼び出されます(デザイナーを使用していない場合は、それを呼び出すのはユーザーの責任です)。

したがって、経験則は

  1. デフォルト値については、コンストラクターで指定します
  2. 「初期化」するには、ISupportInitializeを使用します。

たとえば、そこからPopulateComboBoxを呼び出すだけでなく、これを使用してDrawModeプロパティをOwnerDrawFixedに強制することもできます。これは、継承されたコントロールにとって重要であり、コントロールのユーザーに設計時に他のものを指定させたくないためです(ただしこれにより、異なる値の設計時の「仕様」が正確に妨げられるわけではありませんが、実行時の仕様に関係なく、常に正しい値を強制することになります。)

ノート:

  1. このインターフェイスを実装した後、プロジェクトを再構築してから、デザイナー画面で継承されたコントロールの「ドラッグドロップ」を再度実行する必要がある場合があります。自動的に作成されたデザイナーコードを調べて、EndInitが実際に呼び出されていることを確認できます。
  2. 前述のように、ISupportInitializeは設計者によって使用されます。Designerを使用しない場合は、そのメソッドを呼び出すのはあなたの責任です。
于 2012-06-28T09:50:16.410 に答える
0

後で動的に値を変更する予定がない限り、サブ新規にあるはずです。

また、なぜアレイをクリアする必要があるのか​​わかりません。GCがそれを処理します。

于 2012-06-27T23:32:37.030 に答える
0

あなたの問題を調べたとき、私は当初、DesignModeプロパティを使用すると、コントロールがフォームに追加されたときにItemArrayが作成されないだろうと思っていました...しかし、それは機能しませんでした。

DesignMode次に、Visual Studioの別のインスタンスをプロジェクトにアタッチし、それが常にfalseに設定されていることに気付きました。フォームに追加されたときにコントロールがItemArrayを作成しないようにするための一意の別のプロパティを見つけることができませんでした(これがデータの最初の読み込みの原因です)。

通常のComboBoxはプロパティまたは接続されたデータソースから配列をロードするだけですが、実行しようとしていることは、データソースをコントロールに組み込み、作成するたびに実行するという点で独特です。

現時点での私の唯一の提案はPopulateComboBox、コントロールのコンストラクターからメソッドを取り出し、代わりに親フォームのコンストラクターで呼び出すか、動的に作成してフォームに追加することです。

すなわち

Public Class Form1
    Public Sub New()
        InitializeComponent()
        ComboBoxExColors1.PopulateComboBox()
    End Sub
End Class
于 2012-06-28T06:09:11.460 に答える