2009-12-09 3 views
2

J'ai un CheckedListBox. Je voudrais être en mesure de sélectionner des éléments lorsque je clique sur le texte, mais cochez/décochez-les lorsque je clique sur la case à cocher sur la gauche. Si je règle CheckOnClick, les éléments sont cochés et décochés chaque fois que je clique, même sur le texte, ce qui n'est pas bon. Mais si j'efface CheckOnClick, je dois cliquer deux fois pour cocher et décocher. Ma première pensée est de gérer les événements MouseClick ou MouseDown et d'appeler IndexFromPoint pour savoir quelle ligne est cliquée. Alors je devinerais juste que la case à cocher est sur la gauche, de x = position de 0 à, par exemple, ItemRectangle.Height. En fonction de la distance à partir de la gauche, je pourrais sélectionner ou cocher/décocher.Comment puis-je CheckOnClick dans une CheckedListbox, mais uniquement lorsque la case est cochée?

La question est de savoir s'il existe un meilleur moyen de déterminer si la souris est sur la case à cocher ou sur le texte. Différents styles peuvent avoir différentes tailles et cases à cocher pourraient les mettre à gauche, à droite, etc ...

Répondre

2

J'ai écrit ceci et cela semble fonctionner, grâce à SLaks. Pour utiliser ceci, CheckOnClick doit être vrai et CheckInCheckbox aussi. Hériter de CheckedListbox.

L'idée est de déterminer où se trouve la case à cocher et, si le clic est en dehors de la case à cocher, de mettre le checkstate à son opposé. Plus tard, lorsque le clic de souris est reçu par la classe de base, CheckedListbox, il va à nouveau changer l'état de la case à cocher à ce qu'il était. Un peu de hacky changeant l'état d'avant en arrière mais je n'ai pas trouvé d'autre moyen de contourner CheckedListbox en utilisant SelectedIndex pour cocher/décocher, ce qui est en quelque sorte un 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 
1

Voici le code réel (de référence .Net Source) qui peint les cases à cocher, en cas DrawItem:

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); 
} 

EDIT: Voici 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; 
    } 

}

+0

Je ne trouve pas CheckBoxRender.ConvertFromButtonState n'importe où! Est-ce une API interne à laquelle je ne peux pas accéder? – Eyal

Questions connexes