我有一个CheckedListBox。我希望能够在单击文本时选择项目,但在单击左侧的复选框区域时选中/取消选中它们。如果我设置CheckOnClick,那么只要我点击,即使在文本上,也会检查和取消选中项目,这样就没有用了。但如果我清除CheckOnClick,那么我必须单击两次以检查并取消选中。
我的第一个想法是处理MouseClick或MouseDown事件并调用IndexFromPoint来找出单击的行。然后我猜测复选框在左边,从x = 0到位置,比如说ItemRectangle.Height。根据与左边的距离,我可以选择或选中/取消选中。
问题是,是否有更好的方法来确定鼠标是在复选框上还是在文本上方。不同的样式可能有不同大小的复选框,可能会将它们放在左侧,右侧等...
答案 0 :(得分:2)
我写了这个,它似乎工作,感谢SLaks。要使用它,CheckOnClick必须为true,CheckInCheckbox也必须为true。继承自CheckedListbox。
我们的想法是找出复选框的位置,如果点击位于复选框之外,则将checkstate设置为相反的位置。之后,当基类CheckedListbox收到鼠标点击时,它会再次将复选框状态更改回原来的状态。
有点hacky来回改变状态,但我找不到任何其他方法绕过CheckedListbox使用SelectedIndex来检查/取消选中的方式,这也是一种黑客攻击。
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
答案 1 :(得分:1)
以下是在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;
}
}