0

ユーザーがチェックされたコンボボックスのチェックボックスをオンまたはオフにしたときに、ドロップダウンリストが閉じないようにしたいと思います。

Microsoft コードをコピーして、チェック付きコンボボックスを作成しました。そのままでは動かないので、カスタマイズしました。

これが私のコードです:

    Imports System.ComponentModel
Imports System.Collections.ObjectModel

Public Class CheckedCombobox
    Inherits ComboBox
    Public Event ItemCheck(ByVal sender As Object, ByVal e As System.Windows.Forms.ItemCheckEventArgs)

    <Browsable(False)> _
    Public Overloads ReadOnly Property Items() As ComboBox.ObjectCollection
        Get
            Return MyBase.Items
        End Get
    End Property

    Private WithEvents _ItemCollection As New ObservableCollection(Of String)
    Public Property ItemCollection As ObservableCollection(Of String)
        Get
            Return _ItemCollection
        End Get
        Set(value As ObservableCollection(Of String))
            _ItemCollection = value
        End Set
    End Property

    Private _ItemDictionary As New Dictionary(Of String, Boolean)
    Public ReadOnly Property ItemDictionary As Dictionary(Of String, Boolean)
        Get
            Return _ItemDictionary
        End Get
    End Property
    Public ReadOnly Property CheckedItemCollection As List(Of String)
        Get
            Return New List(Of String)(From item In ItemDictionary Where item.Value = True Select item.Key)
        End Get
    End Property
    Public ReadOnly Property UnCheckedItemCollection As List(Of String)
        Get
            Return New List(Of String)(From item In ItemDictionary Where item.Value = False Select item.Key)
        End Get
    End Property

    Public Sub setCheckState(ByVal key As String, ByVal checkstate As Boolean)
        _ItemDictionary(key) = checkstate
    End Sub

    Public Function getCheckState(ByVal key As String)
        Return (_ItemDictionary(key))
    End Function

    Public Sub New()
        Me.DrawMode = Windows.Forms.DrawMode.OwnerDrawVariable
    End Sub

    Protected Overrides Sub OnCreateControl()
        MyBase.OnCreateControl()
        For Each item In ItemCollection
            _ItemDictionary.Add(item, False)
        Next
    End Sub

    Private Sub ItemsChanged(ByVal sender As Object, ByVal e As System.Collections.Specialized.NotifyCollectionChangedEventArgs) Handles _ItemCollection.CollectionChanged

        Select Case e.Action

            Case Specialized.NotifyCollectionChangedAction.Add
                If e.NewStartingIndex = ItemDictionary.Count Then
                    _ItemDictionary.Add(e.NewItems(0), False)
                    MyBase.Items.Add(e.NewItems(0))
                End If

            Case Specialized.NotifyCollectionChangedAction.Remove

                _ItemDictionary.Remove(MyBase.Items(e.OldStartingIndex))
                MyBase.Items.RemoveAt(e.OldStartingIndex)

            Case Specialized.NotifyCollectionChangedAction.Move

                Dim _item As Object = MyBase.Items(e.OldStartingIndex)
                MyBase.Items.RemoveAt(e.OldStartingIndex)
                MyBase.Items.Insert(e.NewStartingIndex, _item)

            Case Specialized.NotifyCollectionChangedAction.Replace

                Throw New Exception("Not implemented yet!")

            Case Specialized.NotifyCollectionChangedAction.Reset

                Dim _checkeditems As New List(Of String)(CheckedItemCollection)

                MyBase.Items.Clear()
                MyBase.Items.AddRange(_ItemCollection.ToArray)

                _ItemDictionary.Clear()
                For Each item In _ItemCollection
                    _ItemDictionary.Add(item, _checkeditems.Contains(item))
                Next

        End Select
        Me.Invalidate()
    End Sub

    Protected Overrides Sub OnDrawItem(ByVal e As System.Windows.Forms.DrawItemEventArgs)
        e.DrawBackground()
        Dim p As Point = e.Bounds.Location

        If e.Index >= 0 Then
            p.Offset(1, 1)
            If getCheckState(MyBase.Items(e.Index)) Then
                CheckBoxRenderer.DrawCheckBox(e.Graphics, p, VisualStyles.CheckBoxState.CheckedNormal)
            Else
                CheckBoxRenderer.DrawCheckBox(e.Graphics, p, VisualStyles.CheckBoxState.UncheckedNormal)
            End If

            p.Offset(12, 0)
            e.Graphics.DrawString(MyBase.GetItemText(Me.Items(e.Index)), e.Font, New SolidBrush(e.ForeColor), p.X, p.Y)
        End If
        If e.State = DrawItemState.Selected Then
            e.DrawFocusRectangle()
        End If
        MyBase.OnDrawItem(e)
    End Sub

    Private Sub checkedChanged(ByVal index As Integer)
        Dim checked As Boolean = _ItemDictionary(MyBase.Items.Item(index))
        If checked Then
            _ItemDictionary(MyBase.Items.Item(index)) = False
            RaiseEvent ItemCheck(Me, New ItemCheckEventArgs(index, CheckState.Unchecked, CheckState.Checked))
        Else
            _ItemDictionary(MyBase.Items.Item(index)) = True
            RaiseEvent ItemCheck(Me, New ItemCheckEventArgs(index, CheckState.Checked, CheckState.Unchecked))
        End If
        Me.Invalidate()
    End Sub

    Private n As nWindow = Nothing
    Private Const WM_CTLCOLORLISTBOX As Integer = &H134
    Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
        MyBase.WndProc(m)
        If m.Msg = WM_CTLCOLORLISTBOX Then
            If n Is Nothing Then
                n = New nWindow(Me)
                n.AssignHandle(m.LParam)
                AddHandler n.checkedChanged, AddressOf checkedChanged
            End If
        End If
    End Sub

    Private Sub CheckedCombobox_Click(sender As Object, e As System.EventArgs) Handles Me.SelectedIndexChanged
        Debugger.Break()
    End Sub
End Class

Public Class nWindow
    Inherits NativeWindow

    Private Const WM_LBUTTONDOWN As Integer = &H201

    Private _combobox As CheckedCombobox

    Public Event checkedChanged(ByVal index As Integer)

    Public Sub New(ByVal cb As CheckedCombobox)
        _combobox = cb
    End Sub

    Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
        If m.Msg = WM_LBUTTONDOWN Then
            Dim itemHeight As Integer = _combobox.ItemHeight
            If New Point(m.LParam.ToInt32).Y \ itemHeight <= _combobox.Items.Count - 1 And New Point(m.LParam.ToInt32).Y \ itemHeight >= 0 Then
                If New Point(m.LParam.ToInt32).X >= 1 And New Point(m.LParam.ToInt32).X <= 11 Then
                    RaiseEvent checkedChanged(_combobox.SelectedIndex)
                End If
            End If
        End If
        MyBase.WndProc(m)
    End Sub

End Class
4

1 に答える 1

0

以下のコードは正しく動作しているようです。それは私がやろうとしていることをします。

(注: 変更されたルーチンのみを示しています)

 Private Sub checkedChanged(ByVal index As Integer)
    Dim checked As Boolean = _ItemDictionary(MyBase.Items.Item(index))
    If checked Then
        _ItemDictionary(MyBase.Items.Item(index)) = False
        RaiseEvent ItemCheck(Me, New ItemCheckEventArgs(index, CheckState.Unchecked, CheckState.Checked))
    Else
        _ItemDictionary(MyBase.Items.Item(index)) = True
        RaiseEvent ItemCheck(Me, New ItemCheckEventArgs(index, CheckState.Checked, CheckState.Unchecked))
    End If
    Me.SelectedIndex = -1
End Sub



Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
    If m.Msg = WM_LBUTTONDOWN Then
        Dim itemHeight As Integer = _combobox.ItemHeight
        If New Point(m.LParam.ToInt32).Y \ itemHeight <= _combobox.Items.Count - 1 And New Point(m.LParam.ToInt32).Y \ itemHeight >= 0 Then
            If New Point(m.LParam.ToInt32).X >= 1 And New Point(m.LParam.ToInt32).X <= 11 Then
                RaiseEvent checkedChanged(_combobox.SelectedIndex)
                Return
            End If
        End If
    End If
    MyBase.WndProc(m)
End Sub

MyBase.WndProc() を呼び出さないことについて 100% 確信があるわけではありませんが、まだ副作用に気付きませんでした。

于 2013-02-07T11:32:18.243 に答える