【问题标题】:How do I CheckOnClick in a CheckedListbox but only when over the checkbox?如何在 CheckedListbox 中 CheckOnClick 但仅在复选框上方时?
【发布时间】:2009-12-09 23:53:43
【问题描述】:

我有一个 CheckedListBox。我希望能够在单击文本时选择项目,但在单击左侧的复选框区域时选中/取消选中它们。如果我设置 CheckOnClick ,那么每当我单击时,即使在文本上,项目也会被选中和取消选中,所以这不好。但是如果我清除 CheckOnClick 则我必须单击两次才能选中和取消选中。

我的第一个想法是处理 MouseClick 或 MouseDown 事件并调用 IndexFromPoint 来找出单击了哪一行。然后我会猜测复选框在左侧,从 x=position 从 0 到 ItemRectangle.Height。根据与左侧的距离,我可以选择或选中/取消选中。

问题是是否有更好的方法来确定鼠标是在复选框上还是在文本上。不同的样式可能有不同大小的复选框,并可能将它们放在左侧、右侧等...

【问题讨论】:

  • 除非你真的使用CheckedListBox控件,我认为你最好使用ListView控件和CheckBoxes属性,然后你会得到你想要的行为。然后,只需使用控件的样式属性使其看起来像一个简单的CheckedListBox
  • @FabienTeulieres,您能否展示一些示例或任何链接?谢谢你的建议。因为我无法完全自定义它以使其看起来像我想要的那样。

标签: .net checkedlistbox


【解决方案1】:

感谢 SLaks,我写了这个,它似乎可以工作。要使用它,CheckOnClick 必须为 true,CheckInCheckbox 也必须为 true。从 CheckedListbox 继承。

这个想法是找出复选框的位置,如果点击在复选框之外,则将检查状态设置为相反的状态。稍后,当基类 CheckedListbox 接收到鼠标点击时,它会再次将复选框状态更改回原来的状态。

有点 hacky 来回改变状态,但我找不到任何其他方法来绕过 CheckedListbox 使用 SelectedIndex 来检查/取消选中的方式,这也是一种 hack。

Private MyCheckInCheckbox As Boolean = False

''' <summary>
''' Only change the checkbox value when clicking on the box
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property CheckInCheckbox() As Boolean
    Get
        Return MyCheckInCheckbox
    End Get
    Set(ByVal value As Boolean)
        MyCheckInCheckbox = value
    End Set
End Property

Private Sub MyCheckedListBox_MouseClick(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseClick
    If CheckInCheckbox Then
        Dim border As Integer = 1
        Dim index As Integer = IndexFromPoint(e.Location)
        If index <> ListBox.NoMatches Then
            Dim bounds As Rectangle = Me.GetItemRectangle(index)
            Dim idealCheckSize As Integer
            If Application.RenderWithVisualStyles Then
                Dim cbState As VisualStyles.CheckBoxState
                Select Case Me.GetItemCheckState(index)
                    Case CheckState.Checked
                        cbState = VisualStyles.CheckBoxState.CheckedNormal
                    Case CheckState.Indeterminate
                        cbState = VisualStyles.CheckBoxState.MixedNormal
                    Case CheckState.Unchecked
                        cbState = VisualStyles.CheckBoxState.UncheckedNormal
                End Select
                Dim g As Graphics = Me.CreateGraphics
                idealCheckSize = CheckBoxRenderer.GetGlyphSize(g, cbState).Width
                g.Dispose()
            End If
            Dim centeringFactor As Integer = Math.Max((bounds.Height - idealCheckSize) \ 2, 0)
            If centeringFactor + idealCheckSize > bounds.Height Then
                centeringFactor = bounds.Height - idealCheckSize
            End If
            Dim box As Rectangle = New Rectangle(bounds.X + border, bounds.Y + centeringFactor, idealCheckSize, idealCheckSize)
            If RightToLeft = Windows.Forms.RightToLeft.Yes Then
                box.X = bounds.X + bounds.Width - idealCheckSize - border
            End If
            If Not box.Contains(e.Location) Then
                Me.SelectedIndex = index
                SetItemChecked(index, Not GetItemChecked(index))
            End If
        End If
    End If
End Sub

【讨论】:

    【解决方案2】:

    这是在 DrawItem 事件中绘制复选框的实际代码(来自 .Net 参考源):

    Rectangle bounds = e.Bounds;
    int border = 1; 
    int height = Font.Height + 2 * border;
    
    // set up the appearance of the checkbox 
    // [Snip]
    
    // If we are drawing themed CheckBox .. get the size from renderer.. 
    // the Renderer might return a different size in different DPI modes.. 
    if (Application.RenderWithVisualStyles) {
       VisualStyles.CheckBoxState cbState = CheckBoxRenderer.ConvertFromButtonState(state, false, ((e.State & DrawItemState.HotLight) == DrawItemState.HotLight)); 
       idealCheckSize = (int)(CheckBoxRenderer.GetGlyphSize(e.Graphics, cbState)).Width;
    }
    
    // Determine bounds for the checkbox 
    //
    int centeringFactor = Math.Max((height - idealCheckSize) / 2, 0); 
    
    // Keep the checkbox within the item's upper and lower bounds
    if (centeringFactor + idealCheckSize > bounds.Height) { 
        centeringFactor = bounds.Height - idealCheckSize;
    }
    
    Rectangle box = new Rectangle(bounds.X + border, 
                                  bounds.Y + centeringFactor,
                                  idealCheckSize, 
                                  idealCheckSize); 
    
    if (RightToLeft == RightToLeft.Yes) { 
        // For a RightToLeft checked list box, we want the checkbox
        // to be drawn at the right.
        // So we override the X position.
        box.X = bounds.X + bounds.Width - idealCheckSize - border; 
    }
    
    // Draw the checkbox. 
    //
    if (Application.RenderWithVisualStyles) {
        VisualStyles.CheckBoxState cbState = CheckBoxRenderer.ConvertFromButtonState(state, false, ((e.State & DrawItemState.HotLight) == DrawItemState.HotLight));
        CheckBoxRenderer.DrawCheckBox(e.Graphics, new Point(box.X, box.Y), cbState); 
    }
    else { 
        ControlPaint.DrawCheckBox(e.Graphics, box, state); 
    }
    

    编辑:这里是CheckBoxRenderer.ConvertFromButtonState

    internal static CheckBoxState ConvertFromButtonState(ButtonState state, bool isMixed, bool isHot) { 
       if (isMixed) {
           if ((state & ButtonState.Pushed) == ButtonState.Pushed) {
               return CheckBoxState.MixedPressed;
           } 
           else if ((state & ButtonState.Inactive) == ButtonState.Inactive) {
               return CheckBoxState.MixedDisabled; 
           } 
           else if (isHot) {
               return CheckBoxState.MixedHot; 
           }
    
           return CheckBoxState.MixedNormal;
       } 
       else if ((state & ButtonState.Checked) == ButtonState.Checked) {
           if ((state & ButtonState.Pushed) == ButtonState.Pushed) { 
               return CheckBoxState.CheckedPressed; 
           }
           else if ((state & ButtonState.Inactive) == ButtonState.Inactive) { 
               return CheckBoxState.CheckedDisabled;
           }
           else if (isHot) {
               return CheckBoxState.CheckedHot; 
           }
    
           return CheckBoxState.CheckedNormal; 
       }
       else { //unchecked 
           if ((state & ButtonState.Pushed) == ButtonState.Pushed) {
               return CheckBoxState.UncheckedPressed;
           }
           else if ((state & ButtonState.Inactive) == ButtonState.Inactive) { 
               return CheckBoxState.UncheckedDisabled;
           } 
           else if (isHot) { 
               return CheckBoxState.UncheckedHot;
           } 
    
           return CheckBoxState.UncheckedNormal;
       }
    

    }

    【讨论】:

    • 我在任何地方都找不到 CheckBoxRender.ConvertFromButtonState!是我无法访问的内部 API 吗?
    猜你喜欢
    • 2012-10-15
    • 1970-01-01
    • 1970-01-01
    • 2019-07-16
    • 1970-01-01
    • 1970-01-01
    • 2021-03-08
    • 2021-07-21
    • 1970-01-01
    相关资源
    最近更新 更多