CheckedListBox Control - Only checking the checkbox when the actual checkbox is clicked
Asked Answered
L

6

15

I'm using a CheckedListBox control in a small application I'm working on. It's a nice control, but one thing bothers me; I can't set a property so that it only checks the item when I actually check the checkbox. What's the best way to overcome this? I've been thinking about getting the position of the mouseclick, relative from the left side of the checkbox. Which works partly, but if I would click on an empty space, close enough to the left the current selected item would still be checked. Any ideas regarding this?

Loci answered 19/1, 2010 at 14:2 Comment(3)
you could use an extra label, just the checkbox list, and then create labels,.. it's not that nice solved but it works :>Protector
Maybe I'm missing something. What is happening now when you check the box? Nothing? Is it checking something by default? What is happening that you want to stop happening?Tag
I only want the box to be checked when I click the box itself, not the line. Imagine it looking like: [ ] Item1 Currently, the box gets checked when clicking on the entire item, but I don't want that. I only want it to be clicked when I click the box itself, not the descriptive text next to it.Loci
F
9

Well, it is quite ugly, but you could calculate mouse hit coordinates against rectangles of items by hooking on CheckedListBox.MouseDown and CheckedListBox.ItemCheck like the following

/// <summary>
/// In order to control itemcheck changes (blinds double clicking, among other things)
/// </summary>
bool AuthorizeCheck { get; set; }

private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e)
{
    if(!AuthorizeCheck)
        e.NewValue = e.CurrentValue; //check state change was not through authorized actions
}

private void checkedListBox1_MouseDown(object sender, MouseEventArgs e)
{
    Point loc = this.checkedListBox1.PointToClient(Cursor.Position);
    for (int i = 0; i < this.checkedListBox1.Items.Count; i++)
    {
        Rectangle rec = this.checkedListBox1.GetItemRectangle(i);
        rec.Width = 16; //checkbox itself has a default width of about 16 pixels

        if (rec.Contains(loc))
        {
            AuthorizeCheck = true;
            bool newValue = !this.checkedListBox1.GetItemChecked(i);
            this.checkedListBox1.SetItemChecked(i, newValue);//check 
            AuthorizeCheck = false;

            return;
        }
    }
}
Fluting answered 20/1, 2010 at 5:19 Comment(2)
Yeah, like I said in the OP, I was thinking about something like this as well, but since it doesn't feel really good I started looking for alternatives :)Loci
Thanks, it just works! Some optimizations are possible, but the idea works!Condorcet
A
14

I know this thread's a bit old, but I don't think it's a problem to offer another solution:

private void checkedListBox1_MouseClick(object sender, MouseEventArgs e)
{
    if ((e.Button == MouseButtons.Left) & (e.X > 13))
    {
        this.checkedListBox1.SetItemChecked(this.checkedListBox1.SelectedIndex, !this.checkedListBox1.GetItemChecked(this.checkedListBox1.SelectedIndex));
    }
}

(With the value of CheckOnClick = True).

You could use that thingy with the rectangle, but why make it more complex the it needs to.

Antiworld answered 2/1, 2011 at 18:6 Comment(0)
F
9

Well, it is quite ugly, but you could calculate mouse hit coordinates against rectangles of items by hooking on CheckedListBox.MouseDown and CheckedListBox.ItemCheck like the following

/// <summary>
/// In order to control itemcheck changes (blinds double clicking, among other things)
/// </summary>
bool AuthorizeCheck { get; set; }

private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e)
{
    if(!AuthorizeCheck)
        e.NewValue = e.CurrentValue; //check state change was not through authorized actions
}

private void checkedListBox1_MouseDown(object sender, MouseEventArgs e)
{
    Point loc = this.checkedListBox1.PointToClient(Cursor.Position);
    for (int i = 0; i < this.checkedListBox1.Items.Count; i++)
    {
        Rectangle rec = this.checkedListBox1.GetItemRectangle(i);
        rec.Width = 16; //checkbox itself has a default width of about 16 pixels

        if (rec.Contains(loc))
        {
            AuthorizeCheck = true;
            bool newValue = !this.checkedListBox1.GetItemChecked(i);
            this.checkedListBox1.SetItemChecked(i, newValue);//check 
            AuthorizeCheck = false;

            return;
        }
    }
}
Fluting answered 20/1, 2010 at 5:19 Comment(2)
Yeah, like I said in the OP, I was thinking about something like this as well, but since it doesn't feel really good I started looking for alternatives :)Loci
Thanks, it just works! Some optimizations are possible, but the idea works!Condorcet
S
6

Another solution is to simply use a Treeview.
Set CheckBoxes to true, ShowLines to false, and ShowPlusMinus to false and you have basically the same thing as a CheckedListBox. The items are only checked when the actual CheckBox is clicked.

The CheckedListBox is much more simplistic, but the TreeView offers a lot of options that can potentially be better suited for your program.

Sleazy answered 10/2, 2012 at 20:51 Comment(0)
O
3

I succesfully used this property:

CheckedBoxList.CheckOnClick

https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.checkedlistbox.checkonclick?view=netframework-4.7.2

Opalopalesce answered 19/1, 2019 at 16:54 Comment(0)
I
0

The text for a checkbox in a CheckedListBox is rendered by default is to place an HTML label after the checkbox input and set the label's "for" attribute to the ID of the checkbox.

When a label is denoting an element that it is "for," clicking on that label tells the browser to focus on that element, which is what you're seeing.

Two options are to render your own list with separate CheckBox controls and text (not as the Text property of the CheckBox, as that does the same thing as the CheckBoxList) if the list is static or to use something like a Repeater if the list is dynamic.

Isobel answered 19/1, 2010 at 14:51 Comment(2)
It's not a webform, but a winform :) But I get your drift. The focussing is fine and actually what I want, I just don't want the checkbox checked when clicking on the item itself. Seems I'm gonna fiddle around with a custom control :)Loci
Ok, it's hard to tell when there was only c# and CheckedListBox as the tags. I went ahead and added winforms.Isobel
T
0

Try this. Declare iLastIndexClicked as a form-level int variable.

private void chklst_MouseClick(object sender, MouseEventArgs e)
{
  Point p = chklst.PointToClient(MousePosition);
  int i = chklst.IndexFromPoint(p);
  if (p.X > 15) { return; } // Body click. 
  if (chklst.CheckedIndices.Contains(i)){ return; } // If already has focus click anywhere works right.
 if (iLastIndexClicked == i) { return; } // native code will check/uncheck
  chklst.SetItemChecked(i, true);  
  iLastIndexClicked = i;
}

Just checking to see if the user clicked in the leftmost 15 pixels of the checked list (the check box area) works at all times except re-checking a currently selected item. Storing the last index and exiting without changing lets the native code handle that properly, trying to set it to checked in that case turns it on and it just turns back off when the "ItemCheck" code runs.

Tacet answered 9/1, 2018 at 19:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.