views:

920

answers:

6

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?

EDIT: 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?

+2  A: 

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

Ged
WinForms app, not ASP, but thanks anyway.
Craig Johnston
+1  A: 

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);
        }
    }
volody
See edit to question above.
Craig Johnston
+3  A: 

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
Dan Tao
A: 

Validation Scenario Suggestion :

  • If your winform has an Submit/Save button, I would like the application to show an error when the button is cliked (provided there is a label saying that there should be atleast one item selected). The error message need not be a MessageBox, it could a red label showing the error description in the form itself

  • If there are no buttons you can hold on to, then do the validation as when users click on the items. Using ItemCheck event, check if there is atleast one item checked. If not, show the error label.

Code :

private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e)
{
    if (checkedListBox1.CheckedIndices.Count == 1 &&
        e.NewValue == CheckState.Unchecked &&
        e.CurrentValue == CheckState.Checked)
    {
        //Show error label in red
    }
}
Xinxua
+2  A: 

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
Hans Passant
A: 

I would use the ItemCheck event to set the Button.Enabled = false when there is not at least one item checked, and Button.Enabled = true when there is at least one item checked (assuming an Ok button or something alike).

Will Marcouiller