How to require CheckedListBox to have at least one item selected

12,104

Solution 1

Either idea -- preventing the user from unchecking the last checked item, or validating that at least one item is checked before proceeding -- is fairly straightforward to implement.

How to prevent the user from unchecking the last checked item

1. Make sure at least one item is checked to begin with (e.g., in your form's Load event):

Private Sub frm_Load(ByVal sender As Object, ByVal e As EventArgs)
    clb.SetItemChecked(0, True) ' whatever index you want as your default '
End Sub

2. Add some simple logic to your ItemCheck event handler:

Private Sub clb_ItemCheck(ByVal sender As Object, ByVal e As ItemCheckEventArgs)
    If clb.CheckedItems.Count = 1 Then ' only one item is still checked... '
        If e.CurrentValue = CheckState.Checked Then ' ...and this is it... '
            e.NewValue = CheckState.Checked ' ...so keep it checked '
        End If
    End If
End Sub

How to validate that at least one item is checked

Private Sub btn_Click(ByVal sender As Object, ByVal e As EventArgs)
    ' you could also put the below in its own method '
    If clb.CheckedItems.Count < 1 Then
        MsgBox("You must check at least one item.")
        Return
    End If

    ' do whatever you need to do '
End Sub

Solution 2

You can, but the user can always uncheck it.

The way I would do this would be on submit, loop through the checkbox items and make sure at least one of them was checked (break the loop after as your requirement is met, no need to process the rest of the list.)

If the check fails, make a custom validator visible. Required field validators don't work with Check List Boxes, but you can see how they implemented here:

http://www.codeproject.com/KB/webforms/Validator_CheckBoxList.aspx

Solution 3

This solution should be close. Not 100%, there is no easy way to find out that items were added to an empty list. Add a new class to your project and paste the code shown below. Compile. Drop the new control from the top of your toolbox onto your form. No additional code is needed.

Public Class MyCheckedListBox
    Inherits CheckedListBox

    Protected Overrides Sub OnEnter(ByVal e As System.EventArgs)
        REM Ensure at least one item is checked
        MyBase.OnEnter(e)
        If Me.CheckedIndices.Count = 0 AndAlso Me.Items.Count > 0 Then
            Me.SetItemChecked(0, True)
        End If
    End Sub

    Protected Overrides Sub OnItemCheck(ByVal e As ItemCheckEventArgs)
        REM Prevent unchecking last item
        If Me.CheckedIndices.Count <= 1 AndAlso e.NewValue = CheckState.Unchecked Then e.NewValue = CheckState.Checked
        MyBase.OnItemCheck(e)
    End Sub
End Class

Optional additional override that ensures an item is checked when the form first shows up:

Protected Overrides Sub OnHandleCreated(ByVal e As System.EventArgs)
    MyBase.OnHandleCreated(e)
    If Me.CheckedIndices.Count = 0 AndAlso Me.Items.Count > 0 Then
        Me.SetItemChecked(0, True)
    End If
End Sub

Solution 4

Trap ItemCheck event and verify if last checkbox is unchecked:

    private void Form1_Load(object sender, EventArgs e)
    {
        checkedListBox1.SetItemChecked(0, true);
        checkedListBox1.ItemCheck += checkedListBox1_ItemCheck;
    }

    private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e)
    {
        if (CountChecked() == 1 &&
            e.NewValue == CheckState.Unchecked &&
            e.CurrentValue == CheckState.Checked)
        {
            checkedListBox1.SetItemChecked(0, true);
        }
    }

    private int CountChecked()
    {
        int count = 0;
        for (int i = 0; i < checkedListBox1.Items.Count; i++)
        {
            if (checkedListBox1.GetItemChecked(i) == true)
                count++;
        }
        return count;
    }

Updated: Then you have to make async call to set item check state back.

    private delegate void SetItemCallback(int index);

    private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e)
    {
        if (checkedListBox1.CheckedIndices.Count == 1 &&
            e.NewValue == CheckState.Unchecked &&
            e.CurrentValue == CheckState.Checked)
        {
            int index = checkedListBox1.CheckedIndices[0];
            // Initiate the asynchronous call.
            SetItemCallback d = new SetItemCallback(this.SetItem);
            d.BeginInvoke(index, null, null);
        }
    }
    private void SetItem(int index)
    {
        if (this.checkedListBox1.InvokeRequired)
        {
            SetItemCallback d = new SetItemCallback(SetItem);
            this.Invoke(d, new object[] { index });
        }
        else
        {
            checkedListBox1.SetItemChecked(index, true);
        }
    }
Share:
12,104
CJ7
Author by

CJ7

Updated on June 05, 2022

Comments

  • CJ7
    CJ7 almost 2 years

    With the CheckListBox in VB.NET in VS2005, how would you make it compulsory that at least one item is selected?

    Can you select one of the items at design time to make it the default?

    What would be best way to handle the validation part of this scenario? When should the user be required to tick one of the boxes?