Windows forms checkedlistbox только один элемент

In my CheckedListBox app I want to allow only a single item to be checked. I have these properties already set checkOnClick = true; SelectionMode = One; Any advise will be appreciated

In my CheckedListBox app I want to allow only a single item to be checked.

I have these properties already set

checkOnClick = true;
SelectionMode = One;

Any advise will be appreciated

Breeze's user avatar

Breeze

1,9802 gold badges34 silver badges41 bronze badges

asked May 11, 2012 at 14:28

Ahmed's user avatar

5

uncheck all other items in ItemCheck event as below :

private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e) {
      for (int ix = 0; ix < checkedListBox1.Items.Count; ++ix)
        if (ix != e.Index) checkedListBox1.SetItemChecked(ix, false);
    }

answered May 11, 2012 at 14:30

Zaki's user avatar

ZakiZaki

5,4507 gold badges53 silver badges91 bronze badges

5

the best way to do this is like this:

private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e)
{
    if (e.NewValue == CheckState.Checked && checkedListBox1.CheckedItems.Count > 0)
    {
        checkedListBox1.ItemCheck -= checkedListBox1_ItemCheck;
        checkedListBox1.SetItemChecked(checkedListBox1.CheckedIndices[0], false);
        checkedListBox1.ItemCheck += checkedListBox1_ItemCheck;
    }
}

no looping is always better.

answered Jul 11, 2014 at 8:59

string.Empty's user avatar

string.Emptystring.Empty

10.2k4 gold badges42 silver badges67 bronze badges

  • Remove From My Forums

 locked

CheckedListBox — allow only one item to be selected

  • Question

  • Hi,

    I am using CheckedListBox and I want to allow the user to select only one item in the listbox.

    I used  cbList.SelectionMode = SelectionMode.One; to disable it, but it doesnt work

    I am still able to select second item after I select the first item..

    am I missing anything ?

    Thank you,

Answers

  • Just uncheck the other items when you see one getting checked:

        private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e) {
          if (e.NewValue == CheckState.Checked)
            for (int ix = 0; ix < checkedListBox1.Items.Count; ++ix)
              if (e.Index != ix) checkedListBox1.SetItemChecked(ix, false);
        }

6 / 8 / 0

Регистрация: 30.04.2011

Сообщений: 188

1

.NET 4.x

18.12.2013, 09:07. Показов 18090. Ответов 4


Visual Studio 2012
Компонент: checkedListBox
У него есть свойство: «SelectionMode». У него есть вариант «One», но даже так можно выбирать несколько элементов из списка. А судя по описанию с помощью этого свойства можно ограничить выбор лишь одним элементом.
Я чего-то не понимаю или баг?

__________________
Помощь в написании контрольных, курсовых и дипломных работ, диссертаций здесь



0



Эксперт .NET

16746 / 12498 / 3285

Регистрация: 17.09.2011

Сообщений: 20,732

18.12.2013, 10:55

2

Под словом «выбирать» вы подразумеваете выделять мышью или отмечать чекбокс?
Если первое, то это баг, если второе, то все работает как надо.



0



6 / 8 / 0

Регистрация: 30.04.2011

Сообщений: 188

18.12.2013, 11:04

 [ТС]

3

Тогда как сделать, что бы можно было отметить только один чекбокс?



0



kolorotur

Эксперт .NET

16746 / 12498 / 3285

Регистрация: 17.09.2011

Сообщений: 20,732

18.12.2013, 13:06

4

Подпишитесь на событие списка ItemCheck и в обработчике пропишите такой код:

C#
1
2
3
4
5
var list = sender as CheckedListBox;
if (e.NewValue == CheckState.Checked)
    foreach (int index in list.CheckedIndices)
        if (index != e.Index)
            list.SetItemChecked(index, false);



1



moverast

6 / 8 / 0

Регистрация: 30.04.2011

Сообщений: 188

18.12.2013, 13:13

 [ТС]

5

Что-то Ваш код не осилил. Сделал так:

C#
1
2
3
4
5
6
7
8
9
10
        private void checkedListBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            //Если отмечено больше 2 элементов, то снимаем выделение со всех и отмечаем текущий.
            if (checkedListBox1.CheckedItems.Count > 1)
            {
                for (int i = 0; i < checkedListBox1.Items.Count; i++)
                    checkedListBox1.SetItemChecked(i, false);
                checkedListBox1.SetItemChecked(checkedListBox1.SelectedIndex, true);
            }
        }



4



Последнее обновление: 31.10.2015

Элемент CheckedListBox представляет симбиоз компонентов ListBox и CheckBox. Для каждого элемента такого списка определено специальное поле CheckBox,
которое можно отметить.

Все элементы задаются в CheckedListBox задаются в свойстве Items. Также, как и для элементов ListBox и
ComboBox, мы можем задать набор элементов. По умолчанию для каждого добавляемого нового элемента флажок не отмечен:

Элемент CheckedListBox в Windows Forms

Чтобы поставить отметку в checkBox рядом с элементом в списке, нам надо сначала выделить элемент и дополнительным щелчком уже установить
флажок. Однако это не всегда удобно, и с помощью свойства CheckOnClick и установке для него значения true мы
можем определить сразу выбор элемента и установку для него флажка в один клик.

Другое свойство MultiColumn при значении true позволяет сделать многоколоночный список, если элементы
не помещаются по длине:

Свойство MultiColumn в CheckedListBox

Выделенный элемент мы также можем получить с помощью свойства SelectedItem, а его индекс — с помощью свойства
SelectedIndex. Но это верно только, если для свойства SelectionMode установлено
значение One, что подразумевает выделение только одного элемента.

При установке для свойства SelectionMode значений MultiSmple и MultiExtended можно выбрать
сразу несколько элементов, и тогда все выбранные элементы будут доступны в свойстве SelectedItems, а их
индексы — в свойстве SelectedIndeces.

И поскольку мы можем поставить отметку не для всех выбранных элементов, то чтобы отдельно получить отмеченные элементы, у CheckedListBox
имеются свойства CheckedItems и CheckedIndices.

Для добавления и удаления элементов в CheckedListBox определены все те же методы, что и в LstBox:

  • Add(item): добавляет один элемент

  • AddRange(array): добавляет в список массив элементов

  • Insert(index, item): добавляет элемент по определенному индексу

  • Remove(item): удаляет элемент

  • RemoveAt(index): удаляет элемент по определенному индексу

  • Clear(): полностью очищает список

SetItemChecked и SetItemCheckState

К особенностям элемента можно отнести методы SetItemChecked и SetItemCheckState.
Метод SetItemChecked позволяет установить или сбросить отметку на одном из элементов. А метод SetItemCheckState
позволяет установить флажок в одно из трех состояний: Checked (отмечено), Unchecked (неотмечено) и Indeterminate (промежуточное состояние):

checkedListBox1.SetItemChecked(0, true);
checkedListBox1.SetItemCheckState(1, CheckState.Indeterminate);

Программный выбор элемента в CheckedListBox

I have a check list box control and I want to select only one item at a time and I am currently using this code to do the same.

private void CLSTVariable_ItemCheck(object sender, ItemCheckEventArgs e)
{
  // Local variable
  int ListIndex;

  CLSTVariable.ItemCheck -= CLSTVariable_ItemCheck;

  for (ListIndex = 0; 
       ListIndex < CLSTVariable.Items.Count; 
       ListIndex++)
  {        
    // Unchecked all items that is not currently selected
    if (CLSTVariable.SelectedIndex != ListIndex)
    {
      // set item as unchecked
      CLSTVariable.SetItemChecked(ListIndex, false);
    } // if
    else
    {
      // set selected item as checked
      CLSTVariable.SetItemChecked(ListIndex, true);
    }
  } // for
  CLSTVariable.ItemCheck += CLSTVariable_ItemCheck;  
}

this code is working fine.

but problem is that when I click again and again on selected item then that selected item should not be unchecked, means at least one item should be checked always…

akjoshi's user avatar

akjoshi

15.1k13 gold badges104 silver badges120 bronze badges

asked Mar 10, 2011 at 8:07

Shashi Jaiswal's user avatar

4

I agree with commentators above — you should consider using radiobuttons. But if you really need CheckedListBox, then use this ItemChecked event handler instead:

private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e)
{
    if (checkedListBox1.CheckedItems.Count == 1)
    {
        Boolean isCheckedItemBeingUnchecked = (e.CurrentValue == CheckState.Checked);
        if (isCheckedItemBeingUnchecked)
        {
            e.NewValue = CheckState.Checked;
        }
        else
        {
            Int32 checkedItemIndex = checkedListBox1.CheckedIndices[0];
            checkedListBox1.ItemCheck -= checkedListBox1_ItemCheck;
            checkedListBox1.SetItemChecked(checkedItemIndex, false);
            checkedListBox1.ItemCheck += checkedListBox1_ItemCheck;
        }

        return;
    }
}

answered Mar 10, 2011 at 8:34

Loki Kriasus's user avatar

Loki KriasusLoki Kriasus

1,28210 silver badges22 bronze badges

2

Well, it was an answer to me! I couldn’t get the above code to work in the checkedListBox1_ItemCheck. I had to modify a portion of it ans include it in the checkedListBox1_SelectedIndexChanged event. But I couldn’t remove the original code all together. Here is what I’ve added…

private void checkedListBox1_SelectedIndexChanged(object sender, EventArgs e)
    {
        if (checkedListBox1.CheckedItems.Count > 1)
        {
            Int32 checkedItemIndex = checkedListBox1.CheckedIndices[0];
            checkedListBox1.ItemCheck -= checkedListBox1_ItemCheck;
            checkedListBox1.SetItemChecked(checkedItemIndex, false);
            checkedListBox1.ItemCheck += checkedListBox1_ItemCheck;
        }
    }

Which is basically, if you have more than 1 box checked, switch the last one for the new one. I’m curious why the original code didn’t work. And why it has to be there for my new code to work? Thank you.

answered Apr 24, 2012 at 3:32

topofsteel's user avatar

topofsteeltopofsteel

1,2376 gold badges16 silver badges25 bronze badges

I found this code it work so well

private void chkboxmov_ItemCheck(object sender, ItemCheckEventArgs e)
{
    for (int ix = 0; ix < chkboxmov.Items.Count; ++ix)
        if (ix != e.Index)
            chkboxmov.SetItemChecked(ix, false);
}

everton's user avatar

everton

7,4232 gold badges28 silver badges42 bronze badges

answered Jan 13, 2014 at 18:45

hank's user avatar

«at least one item should be checked always»

The current solution (the last one) allows items to be checked off. If your purpose is to select exactly one item at all times, use this as a MouseUp event,

    private void ChklbBatchType_MouseUp(object sender, MouseEventArgs e)
    {
        int index = ((CheckedListBox)sender).SelectedIndex;
        for (int ix = 0; ix < ((CheckedListBox)sender).Items.Count; ++ix)
            if (index != ix) { ((CheckedListBox)sender).SetItemChecked(ix, false);   }
              else ((CheckedListBox)sender).SetItemChecked(ix, true);
    }

answered Dec 4, 2019 at 14:01

Goodies's user avatar

GoodiesGoodies

1,88121 silver badges25 bronze badges

I have a check list box control and I want to select only one item at a time and I am currently using this code to do the same.

private void CLSTVariable_ItemCheck(object sender, ItemCheckEventArgs e)
{
  // Local variable
  int ListIndex;

  CLSTVariable.ItemCheck -= CLSTVariable_ItemCheck;

  for (ListIndex = 0; 
       ListIndex < CLSTVariable.Items.Count; 
       ListIndex++)
  {        
    // Unchecked all items that is not currently selected
    if (CLSTVariable.SelectedIndex != ListIndex)
    {
      // set item as unchecked
      CLSTVariable.SetItemChecked(ListIndex, false);
    } // if
    else
    {
      // set selected item as checked
      CLSTVariable.SetItemChecked(ListIndex, true);
    }
  } // for
  CLSTVariable.ItemCheck += CLSTVariable_ItemCheck;  
}

this code is working fine.

but problem is that when I click again and again on selected item then that selected item should not be unchecked, means at least one item should be checked always…

akjoshi's user avatar

akjoshi

15.1k13 gold badges104 silver badges120 bronze badges

asked Mar 10, 2011 at 8:07

Shashi Jaiswal's user avatar

4

I agree with commentators above — you should consider using radiobuttons. But if you really need CheckedListBox, then use this ItemChecked event handler instead:

private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e)
{
    if (checkedListBox1.CheckedItems.Count == 1)
    {
        Boolean isCheckedItemBeingUnchecked = (e.CurrentValue == CheckState.Checked);
        if (isCheckedItemBeingUnchecked)
        {
            e.NewValue = CheckState.Checked;
        }
        else
        {
            Int32 checkedItemIndex = checkedListBox1.CheckedIndices[0];
            checkedListBox1.ItemCheck -= checkedListBox1_ItemCheck;
            checkedListBox1.SetItemChecked(checkedItemIndex, false);
            checkedListBox1.ItemCheck += checkedListBox1_ItemCheck;
        }

        return;
    }
}

answered Mar 10, 2011 at 8:34

Loki Kriasus's user avatar

Loki KriasusLoki Kriasus

1,28210 silver badges22 bronze badges

2

Well, it was an answer to me! I couldn’t get the above code to work in the checkedListBox1_ItemCheck. I had to modify a portion of it ans include it in the checkedListBox1_SelectedIndexChanged event. But I couldn’t remove the original code all together. Here is what I’ve added…

private void checkedListBox1_SelectedIndexChanged(object sender, EventArgs e)
    {
        if (checkedListBox1.CheckedItems.Count > 1)
        {
            Int32 checkedItemIndex = checkedListBox1.CheckedIndices[0];
            checkedListBox1.ItemCheck -= checkedListBox1_ItemCheck;
            checkedListBox1.SetItemChecked(checkedItemIndex, false);
            checkedListBox1.ItemCheck += checkedListBox1_ItemCheck;
        }
    }

Which is basically, if you have more than 1 box checked, switch the last one for the new one. I’m curious why the original code didn’t work. And why it has to be there for my new code to work? Thank you.

answered Apr 24, 2012 at 3:32

topofsteel's user avatar

topofsteeltopofsteel

1,2376 gold badges16 silver badges25 bronze badges

I found this code it work so well

private void chkboxmov_ItemCheck(object sender, ItemCheckEventArgs e)
{
    for (int ix = 0; ix < chkboxmov.Items.Count; ++ix)
        if (ix != e.Index)
            chkboxmov.SetItemChecked(ix, false);
}

everton's user avatar

everton

7,4232 gold badges28 silver badges42 bronze badges

answered Jan 13, 2014 at 18:45

hank's user avatar

«at least one item should be checked always»

The current solution (the last one) allows items to be checked off. If your purpose is to select exactly one item at all times, use this as a MouseUp event,

    private void ChklbBatchType_MouseUp(object sender, MouseEventArgs e)
    {
        int index = ((CheckedListBox)sender).SelectedIndex;
        for (int ix = 0; ix < ((CheckedListBox)sender).Items.Count; ++ix)
            if (index != ix) { ((CheckedListBox)sender).SetItemChecked(ix, false);   }
              else ((CheckedListBox)sender).SetItemChecked(ix, true);
    }

answered Dec 4, 2019 at 14:01

Goodies's user avatar

GoodiesGoodies

1,88121 silver badges25 bronze badges

Table of Contents

  • CheckedListBox overview
  • Populating
    • With string
    • With classes
  • Checking items
  • Get checked items
  • Disabling items from being checked
  • Check one item
  • Select all option
  • Properties of interest
    • CheckOnClick
    • CheckedItems
    • CheckedIndices
  • Running sample code
  • Required NuGet package
  • Summary
  • See also
  • Source code

This article provides core basics for working with a Windows Form control CheckedListBox from populating with string, setting the DataSource to a DataTable to a List along with getting/setting checked items, finding items, limiting checked items and more. There
will be a discussion on creating a custom CheckedListBox control versus having a decent understanding of the CheckedListBox to decide if a custom CheckedListBox is needed or work with the standard CheckedListBox.

CheckedListBox overview

The CheckedListBox provides the capability to show text along with a Checkbox for each item within the control which allows a user to select one or more items. For example, presenting a options dialog for an application where each item presented in the CheckedListBox
would allow the user to customize the user experience, another case would be to present items for building a product with options to the standard product.

Populating 

There are various ways to populate a CheckedListBox

With string

For fixed items that will not change type in items at design time.

Or use a standard collection like month names.

Imports
System.Globalization

Public
Class
Form1

    Private
Sub
Form1_Load(sender
As
Object
, e As
EventArgs) Handles
MyBase.Load

        MonthsCheckedListBox.Items.AddRange(

            (

               From month
In
CultureInfo.CurrentCulture.DateTimeFormat.MonthNames

               Where
Not
String
.IsNullOrEmpty(month)).ToArray

            )

        MonthsCheckedListBox.SelectedIndex = Now.Month -1

    End
Sub

End
Class

With classes

A class may be used by setting the CheckedListBox.DataSource with a list of a concrete class. To display a specific property for the Text property set the DisplayMember or override the ToString method. 

In the example below the class overrides ToString with ProductName so there is no need to set DisplayMember. If DisplayMember is not set and ToString is not overridden at runtime the object type is shown which does not good.

Namespace
DataClasses

    Public
Class
Product

        Public
Property
ProductID
As
Integer

        Public
Property
ProductName
As
String

        Public
Property
SupplierID
As
Integer
?

        Public
Property
CategoryID
As
Integer
?

        Public
Property
QuantityPerUnit
As
String

        Public
Property
UnitPrice
As
Decimal
?

        Public
Property
UnitsInStock
As
Short
?

        Public
Property
UnitsOnOrder
As
Short
?

        Public
Property
ReorderLevel
As
Short
?

        Public
Property
Discontinued
As
Boolean

        Public
Property
DiscontinuedDate
As
DateTime?

        Public
Overrides
Function
ToString() As
String

            Return
ProductName

        End
Function

    End
Class

End
Namespace

Data is returned from a database table while other options range from reading items from a file or from a service.

Imports
System.Data.SqlClient

Imports
BaseConnectionLibrary

Namespace
DataClasses

    Public
Class
SqlServerOperations

        Inherits
ConnectionClasses.SqlServerConnection

        Public
Sub
New
()

            DefaultCatalog =
"NorthWindAzure1"

            DatabaseServer =
"KARENS-PC"

        End
Sub

        Public
Function
ProductsByCategoryIdentifier(pCategoryIdentifier
As
Integer)
As
List(Of Product)

            Dim
productList As
New
List(Of Product)

            Dim
selectStatement =

                    <SQL>

                    SELECT ProductID

                          ,ProductName

                          ,SupplierID

                          ,QuantityPerUnit

                          ,UnitPrice

                          ,UnitsInStock

                          ,UnitsOnOrder

                          ,ReorderLevel

                          ,Discontinued

                          ,DiscontinuedDate

                      FROM NorthWindAzure1.dbo.Products

                      WHERE CategoryID = <%= pCategoryIdentifier %>

                    </SQL>.Value

            Using cn
As
New
SqlConnection With
{.ConnectionString = ConnectionString}

                Using cmd
As
New
SqlCommand With
{.Connection = cn, .CommandText = selectStatement}

                    Try

                        cn.Open()

                        Dim
reader = cmd.ExecuteReader()

                        While
reader.Read()

                            productList.Add(New
Product() With

                               {

                                   .ProductID = reader.GetInt32(0),

                                   .ProductName = reader.GetString(1),

                                   .Discontinued = reader.GetBoolean(8)

                               })

                        End
While

                    Catch
ex As
Exception

                        mHasException =
True

                        mLastException = ex

                    End
Try

                End
Using

            End
Using

            Return
productList

        End
Function

    End
Class

End
Namespace

In the form an import statement is used as the class above is in a different namespace than the form. The SqlServerOperations class is created as a private variable which means methods are always available in the form. a List of Product is returned and set
as the DataSource for the CheckedListBox.

Imports
CheckOnlyOneItem.DataClasses

Public
Class
Form1

    Private
operations As
SqlServerOperations = New
SqlServerOperations()

    Private
Sub
Form1_Load(sender
As
Object
, e As
EventArgs) Handles
MyBase.Load

        Dim
products = operations.ProductsByCategoryIdentifier(1)

        CheckedListBox1.DataSource = products

    End
Sub

Presentation at runtime.

To select an item, in this case, the selected item, cast to Product as the DataSource is a List(Of Product). Some property is Nothing because they were never set.

To check an item use SetItemChecked which accepts the index of the item to check and the checked state of true or false.

CheckedListBox1.SetItemChecked(0,
True)

Checking items 

For CheckedListBox populated with string cast Items property to string and using a for next to find the item then use the indexer of the for as the index into the CheckedListBox to use SetItemChecked(foundIndex, true or false).

When dealing with a List or a DataTable the following extension methods keep code clean and perform similarly as with using string but with LINQ statements.

Imports
FindAndCheckItem.DataClasses

Namespace
Extensions

    Module
ExtensionMethods

        ''' <summary>

        ''' Find a specific product by name and check or uncheck the item if found

        ''' </summary>

        ''' <param name="sender"></param>

        ''' <param name="pValueToLocate">Product name</param>

        ''' <param name="pChecked">True to check, False to uncheck</param>

        <Runtime.CompilerServices.Extension()>

        Public
Sub
FindItemAndSetChecked(

            sender
As
CheckedListBox,

            pValueToLocate
As
String
,

            Optional
pChecked As
Boolean
=
True)

            Dim
result =

                    (

                        From this
In
sender.Items.Cast(Of Product)().
Select(Function(item, index)
New
With

                           {

                               .Item = item,

                               .Index = index

                           })

                        Where this.Item.ProductName = pValueToLocate

                    ).FirstOrDefault

            If
result IsNot Nothing
Then

                sender.SetItemChecked(result.Index, pChecked)

            End
If

        End
Sub

        ''' <summary>

        ''' Find a specific value by field name and value in a DataTable

        ''' </summary>

        ''' <param name="sender"></param>

        ''' <param name="pValueToLocate">Value to find</param>

        ''' <param name="pFieldName">Field to locate in</param>

        ''' <param name="pChecked">True to check, False to uncheck</param>

        <Runtime.CompilerServices.Extension()>

        Public
Sub
FindItemAndSetChecked(

            sender
As
CheckedListBox,

            pValueToLocate
As
String
,

            pFieldName
As
String
,

            Optional
pChecked As
Boolean
=
True)

            Dim
result =

                    (

                        From this
In
sender.Items.Cast(Of DataRowView)().
Select(Function(item, index)
New
With

                            {.Item = item, .Index = index})

                        Where this.Item.Row.Field(Of
String)(pFieldName).ToLower = pValueToLocate.ToLower

                    ).FirstOrDefault

            If
result IsNot Nothing
Then

                sender.SetItemChecked(result.Index, pChecked)

            End
If

        End
Sub

    End
Module

End
Namespace

To check in the List(Of Product) the following seeks two products and if found checks each product in the CheckedListBox.

Imports
FindAndCheckItem.DataClasses

Imports
FindAndCheckItem.Extensions

Public
Class
Form1

    Private
operations As
SqlServerOperations = New
SqlServerOperations()

    Private
Sub
Form1_Load(sender
As
Object
, e As
EventArgs) Handles
MyBase.Load

        Dim
products = operations.ProductsByCategoryIdentifier(1)

        CheckedListBox1.DataSource = products

        CheckedListBox1.FindItemAndSetChecked("Steeleye Stout")

        CheckedListBox1.FindItemAndSetChecked("Outback Lager")

    End
Sub

End
Class

Get checked items

Use GetItemChecked(desired index). In the following example, ItemCheck event is used to see if the current item is checked and if so append or remove from a multi-line TextBox.

Imports
TrackingCheckedItems.DataClasses

Public
Class
Form1

    Private
operations As
SqlServerOperations = New
SqlServerOperations()

    Private
Sub
Form1_Load(sender
As
Object
, e As
EventArgs) Handles
MyBase.Load

        Dim
products = operations.ProductsByCategoryIdentifier()

        CheckedListBox1.DataSource = products

    End
Sub

    ''' <summary>

    ''' Change Product.Selected dependent on the check state of the current item.

    '''

    ''' Show checked products in the TextBox, in a real application this might be

    ''' done in a button click for making a final selection for the current process.

    '''

    ''' </summary>

    ''' <param name="sender"></param>

    ''' <param name="e"></param>

    Private
Sub
CheckedListBox1_ItemCheck(sender
As
Object, e
As
ItemCheckEventArgs)
Handles
CheckedListBox1.ItemCheck

        CType(CheckedListBox1.Items(e.Index), Product).Selected =
Not
CheckedListBox1.GetItemChecked(e.Index)

        TextBox1.Text =
String.Join(Environment.NewLine,
CType(CheckedListBox1.DataSource, List(Of Product)).

                                       Where(Function(product)
product.Selected).

                                       Select(Function(product)
product.DisplayData).ToArray())

    End
Sub

End
Class

Obtain checked item names the following extension method provides names.

<Runtime.CompilerServices.Extension()>

Public
Function
CheckedItemsNamesList(sender
As
CheckedListBox) As
List(Of String)

    Dim
results As
New
List(Of
String)

    For
index As
Integer
= 0
To
(sender.Items.Count - 1)

        If
sender.GetItemChecked(index) Then

            results.Add(sender.Items(index).ToString)

        End
If

    Next

    Return
results

End
Function

Usage

Dim
productItems = CheckedListBox1.CheckedItemsNamesList()

For
Each
productItem
As
String
In
productItems

    Console.WriteLine(productItem)

Next

The above is works but means to gain access to each product a find operation must be performed on the CheckedListBox.DataSource casted as a List(Of Product), a better method are to get checked indexes of the CheckedListBox using the following language extension.

<Runtime.CompilerServices.Extension()>

Public
Function
CheckedItemsIndexesList(sender
As
CheckedListBox) As
List(Of Integer)

    Dim
results As
New
List(Of
Integer)

    For
index As
Integer
= 0
To
(sender.Items.Count - 1)

        If
sender.GetItemChecked(index) Then

            results.Add(index)

        End
If

    Next

    Return
results

End
Function

The usage which gets each product using the index returned from the extension method above. In this case, the ProductName is shown as ToString has been overridden as shown above in the Product class.

For
index As
Integer
= 0
To
productItems.Count - 1

    Dim
product = CType(CheckedListBox1.Items(index), Product)

    Console.WriteLine(product)

Next

Disabling items from being checked

Consider an application which allows users to purchase items using a CheckedListBox. They open the application on Monday and a product they want appears, they end up thinking about the product and not purchase but come back the next day and the product is not
shown. The developer dynamically populated the CheckedListBox with available items and on the next day it’s out of stock and not shown. This may leave the customer frustrated. Consider checking specific items disallows other options in the CheckedListBox.
There are several options, remove/add using business logic, presenting a message if the item is not available because other options are checked or disable the item(s).

Disabling items coupled with text on the form to indicate why one or more items are not available or use a tooltip. To disable item(s) a

custom CheckedListBox which requires a fair amount of knowledge for coding may be used or write a few lines of code.

In this case for using a standard CheckedListBox against products that are discontinued. Products are loaded including the field which indicates if the product is discontinued (another option is to check stock level available).

Public
Function
ProductsByCategoryIdentifier(pCategoryIdentifier
As
Integer)
As
List(Of Product)

    Dim
productList As
New
List(Of Product)

    Dim
selectStatement =

            <SQL>

            SELECT ProductID

                  ,ProductName

                  ,SupplierID

                  ,QuantityPerUnit

                  ,UnitPrice

                  ,UnitsInStock

                  ,UnitsOnOrder

                  ,ReorderLevel

                  ,Discontinued

                  ,DiscontinuedDate

              FROM NorthWindAzure1.dbo.Products

              WHERE CategoryID = <%= pCategoryIdentifier %>

            </SQL>.Value

    Using cn
As
New
SqlConnection With
{.ConnectionString = ConnectionString}

        Using cmd
As
New
SqlCommand With
{.Connection = cn, .CommandText = selectStatement}

            Try

                cn.Open()

                Dim
reader = cmd.ExecuteReader()

                While
reader.Read()

                    productList.Add(New
Product() With

                                       {

                                           .ProductID = reader.GetInt32(0),

                                           .ProductName = reader.GetString(1),

                                           .Discontinued = reader.GetBoolean(8)

                                       })

                End
While

            Catch
ex As
Exception

                mHasException =
True

                mLastException = ex

            End
Try

        End
Using

    End
Using

    Return
productList

End
Function

Products are loaded by a category identifier, in a real application there would be control, ComboBox or ListBox populated with a List(Of Category), upon selected item change cast the selected item to a Category and get the Category id.

Dim
products = operations.ProductsByCategoryIdentifier(6)

In the form Load or Shown event add items to the CheckedListBox as follows marking discontinued products with an Indeterminate CheckState.

'

' Set state to Indeterminate then enforce the state in ItemCheck event

'

For
Each
product
As
Product
In
products

    If
product.Discontinued Then

        CheckedListBox1.Items.Add(product, CheckState.Indeterminate)

    Else

        CheckedListBox1.Items.Add(product)

    End
If

Next

Subscribe to ItemCheck event of the CheckedListBox, if the CurrentValue is Indeterminate then reset it which keeps the item disabled.

Check one item

Although only permitting one checked item is not something normally done this question has been asked on the web several times. To only permit one checked item subscribe to the ItemCheck event and check the current item NewValue for CheckState.Checked, if so
iterate all items and if a checked item is found other than the current item using SetItemChecked to false.

Imports
CheckOnlyOneItem.DataClasses

Public
Class
Form1

    Private
operations As
SqlServerOperations = New
SqlServerOperations()

    Private
Sub
Form1_Load(sender
As
Object
, e As
EventArgs) Handles
MyBase.Load

        Dim
products = operations.ProductsByCategoryIdentifier(1)

        CheckedListBox1.DataSource = products

    End
Sub

    Private
Sub
CheckedListBox1_ItemCheck(sender
As
Object, e
As
ItemCheckEventArgs)
Handles
CheckedListBox1.ItemCheck

        If
e.NewValue = CheckState.Checked Then

            For
index As
Integer
= 0
To
CheckedListBox1.Items.Count - 1

                If
index <> e.Index Then

                    CheckedListBox1.SetItemChecked(index,
False)

                End
If

            Next

        End
If

    End
Sub

End
Class

Select all option

For providing the ability to check or uncheck all iterate all items in a button click event using SetItemChecked or use a custom CheckedListBox

found here in the included source code.

Properties of interest

CheckOnClick

By default two clicks are required to check or uncheck items, to perform a check or uncheck with one click set the property CheckOnClick in the CheckedListBox property window of in code.

CheckedItems

A collection of checked items, when the DataSource is a List using Cast to cast the items to the specific type

Dim
checkedProducts = CheckedListBox1.CheckedItems.Cast(Of Product)

CheckedIndices

This property provides a collection of checked indexes in the CheckedListBox.

Dim
productIndexes = CheckedListBox1.CheckedIndices

For
index As
Integer
= 0
To
productIndexes.Count - 1

    Dim
product = CType(CheckedListBox1.Items(index), Product)

    Console.WriteLine(product)

Next

Running sample code

  • Create a SQL-Server database and running
    the following script.
  • Each project with SqlServerOperation class change the server name and default catalog as per

    this sample.

  • Right click on solution explorer top node, select «Restore NuGet Packages»
  • Build the solution
  • Run each project.

Required NuGet package

BaseConnectionLibrary — source
code project.

Summary

This article has shown how to utilize a CheckedListBox in common scenarios and several uncommon scenarios using classes as the data source for the CheckedListBox while use of DataTable may be used although using a DataTable has extra baggage not needed e.g.
events, methods to change the state of data rows etc. Keep in mind when considering a CheckedListBox if this is the right option over conventional Checkbox controls.

See also

VB.NET: Defensive data programming (Part 3)
VB.NET Working with parameterized SQL operations part 2
C# DataGridView — ListBox — CheckListBox — ListView move items up/down

Source code

Source code provided in the following
GitHub repository.

Просмотров 1.5к. Обновлено 27 августа 2020

Урок из серии: «Программирование на Visual Basic.NET для школьников»

На этом уроке будет рассмотрен элемент управления Windows Forms CheckedListBox. Он является расширением элемента управления ListBox (Список). Выполняет практически все его функции, а кроме того, в нем может отображаться галочка рядом с элементами списка.

В ходе построения проекта мы создадим компьютерную версию одной из простых головоломок Самуэля Лойда. Лойд – известный американский автор головоломок и шахматных задач – жил и работал во второй половине XIX и в начале XX века.

В этой головоломке  используется список флажков и ещё один дополнительный обыкновенный список. Мы научимся обрабатывать помеченные пользователем элементы в списке флажков CheckedListBox, заодно закрепим свои знания по работе с обыкновенным списком ListBox.

Краткая справочная информация

В элементе управления  CheckedListBox элементы списка можно выделять цветом, кроме того их можно помечать галочкой.

Visual basic.NET. Элемент управления CheckedListBox

В отличии от обычного списка, выделить в списке можно только один элемент. Помеченных галочкой элементов может быть несколько.

Выделенный элемент не обязательно должен быть помеченным элементом. За то, следует ли переключать флажок, когда выделяется элемент, отвечает свойство CheckOnClick. По умолчанию свойство имеет значение False и при выделении элемента флажок не переключается. В этом случае, чтобы переключить флажок, нужно выполнить щелчок в области флажка.

Проект «Головоломка «

Головоломка, которую мы решаем. Из заданного набора чисел надо выбрать те, сумма которых составит 50. Числа такие:

25, 27, 3, 12, 6, 15, 9, 30. 21. 19.

Visual Basic.NET. Головоломка Самуэля Лойда

Несмотря на кажущуюся простоту, головоломка может доставить немало хлопот.

Какие элементы управления нам понадобятся?

Во-первых, мы используем список флажков. Он похож на обычный список, но возле каждого пункта имеется флажок. Его можно установить или сбросить.

Еще нам понадобится обычный список, без флажков. В него мы поместим выбранные числа. Сумму этих чисел покажем в виде надписи. Окно нашей программы должно выглядеть примерно так, как показано на рисунке.

Visual Basic.NET. Списоки

Технология выполнения

    1. Запустите систему Visual Basic и создайте новый проект под именем Головоломка.
    2. Установите на форме элементы управления в соответствии с образцом. Мы уже решили, что нам нужны три элемента управления: список флажков (CheckedListBox), простой список (ListBox) и надпись (Label).
    3. Настройте свойства объектов в соответствии с таблицей:

      Объект Свойства Значения Примечание
      Form1 Text «Головоломка»
      CheckedListBox Text пусто
      Items 25, 27, 3, 12, 6, 15, 9, 30, 21, 19 Щелкните в значении свойства  Items (Коллекция),  на многоточии, появится окно Редактор коллекции строк. Введите числа по одному в строке.
      ListBox1 Text Пусто
      Label Text «Сумма: 0» Начальное значение суммы выбранных чисел (пока ничего не выбрано).
      Alignment MiddleCenter Выравнивание
      по центру

      Окно программы готово и можно приступить к программированию.

    4. Установка и сброс флажков. В окне программы только один элемент управления способен к диалогу – это список флажков. Программа должна что-то делать только в том случае, если дин из флажков устанавливается или сбрасывается. В этом случае возникает событие ItemCheck (Пометка пункта). Нам надо описать реакцию на него.
      • Щелкните на списке флажков правой кнопкой мыши. Выберите в открывшемся контекстном меню пункт View Code (Просмотреть код)
      • В окне кода выберите в раскрывающемся списке справа событие ItemCheck (Пометка пункта). Система Visual Basic выдаст заготовку процедуры для обработки этого события.
        CheckedListBox1_ItemCheck(ByVal sender As Object, ByVal e As
        System.Windows.Forms.ItemCheckEventArgs)

        Информация о пункте списка, для которого был установлен флажок, передается через параметр процедур

        ByVal e As System.Windows.Forms.ItemCheckEventArgs.

        Состояние флажка после изменения состояния флажка хранится в свойстве e.NewValue (Новое значение). Индекс измененной записи хранится в свойстве e.Index.

      • Описываем переменные, которые будут использоваться в программном коде:

        Здесь: S — сумма выбранных чисел, i — переменная цикла.

      • Теперь нам нужно выяснить, установлен был флажок или сброшен. Оператор проверки состояния флажка должен выглядеть так:
        If e.NewValue = CheckState.Checked Then

      • Процедура обработки события вызывается уже после того, как состояние флажка изменилось.
        Если условие истинно (флажок был только что установлен), то  мы должны добавить во второй список новый пункт. Это делается при помощи метода Add. Его параметр — содержимое добавляемого пункта. Нужный нам оператор такой:
        ListBox1.Items.Add(CheckedListBox1.Items(e.Index))

      • Если флажок сброшен, нам будет чуть труднее. Надо удалить пункт из второго списка, а мы не знаем, где именно он находится. Поэтому нам придеться перебрать все элементы второго списка и сравнить его с текущим элементом первого списка. Для этого нам понадобится цикл, выполняющий перебор.Число элементов в списке задается свойством ListCount.Нужные операторы будут выглядеть следующим образом:
         For i = 0 To ListBox1.Items.Count - 1
            If ListBox1.Items(i) = CheckedListBox1.Items(e.Index) Then
              ListBox1.Items.RemoveAt(i)
              Exit For
            End If
         Next i
        End If

        Из значения свойства ListCount мы вычли единичку потому, что нумерация элементов массива ведется не с единицы, а с нуля.
        Если условие ListBox1.Items(i) = CheckedListBox1.Items(e.Index) истинно, значит, нужный элемент найден. Его номер совпадает с текущим значением переменной i.
        В этом случае надо удалить этот элемент из списка. Это делается при помощи метода RemoveItem.

      • Теперь наша программа умеет правильно реагировать на установку или сброс флажка в списке.
    5. Обновление суммы. Итак, списки обновлены. Теперь надо заново подсчитать сумму выбранных чисел. Здесь нас ждет небольшой подводный камень. Хотя элементы списка выглядят как числа, они, на самом деле, являются текстовыми строками. Поэтому при суммировании нам придется воспользоваться функцией Val().Это тоже удобно сделать в цикле. Пусть сумма накапливается в переменной S. Ее расчет можно выполнить так:
      s = 0
      For i = 0 To ListBox1.Items.Count - 1
         s = s + Val(ListBox1.Items(i))
      Next i

  1. Чтобы представить вычисленную сумму в поле надписи , она должна быть текстовой строкой. Поэтому преобразовали ее в текстовый тип с помощью функции STR(). Присоединим ее к тексту подсказки с помощью операции слияния строк:
    Label1.Text = "Сумма: " + Str(s)

  2. Проверка решения. Осталось сделать последний шаг: проверить, решена ли головоломка. Так как значение суммы выбранных чисел у нас уже есть, надо сравнить его с заданным числом 50:

    If S = 50 Then

  3. Если головоломка еще не решена, делать ничего не надо и решение можно продолжить. Если же решение найдено, давайте отключим все элементы управления (изменим свойство Enabled) Кроме того, выведем в поле надписи сообщение «Победа». Это можно сделать так:
    If s = 50 Then
         Label1.Text = "Победа: " + Str(s)
         ListBox1.Enabled = False
         CheckedListBox1.Enabled = False
    End If

  4. Программа готова. На этом наша программа готова, и ее можно испытать. Полный ее текст, как он виден в окне кода, написан ниже.
    Private Sub CheckedListBox1_ItemCheck(ByVal sender As Object, ByVal e As
    System.Windows.Forms.ItemCheckEventArgs) Handles heckedListBox1.ItemCheck
    
            Dim i, s As Integer
            If e.NewValue = CheckState.Checked Then
    
                ListBox1.Items.Add(CheckedListBox1.Items(e.Index))
            Else
    
                For i = 0 To ListBox1.Items.Count - 1
    
                    If ListBox1.Items(i) = CheckedListBox1.Items(e.Index) Then
                        ListBox1.Items.RemoveAt(i)
                        Exit For
                    End If
                Next i
    
            End If
            s = 0
            For i = 0 To ListBox1.Items.Count - 1
                s = s + Val(ListBox1.Items(i))
            Next i
            Label1.Text = "Сумма: " + Str(s)
            If s = 50 Then
                Label1.Text = "Победа: " + Str(s)
                ListBox1.Enabled = False
                CheckedListBox1.Enabled = False
            End If
        End Sub

  5. Нажмите клавишу F5, чтобы запустить программу. При установке флажков выбранные числа попадают во второй список, а при сбросе – удаляются из него.
  6. Когда программа заработает, попробуйте решить головоломку. Это далеко не самая сложная из головоломок Лойда. На всякий случай примите подсказку: чтобы получить сумму 50, надо выбрать три числа.

В этом уроке мы познакомились с элементом управления CheckedListBox (Список флажков), узнали, как обрабатывать в программном коде установку флажков пользователем. Поработали с обычным списком без флажков ListBox, производили в нем поиск, добавление и удаление записей, суммирование записей.

До встречи в следующем уроке.

Понравилась статья? Поделить с друзьями:
  • Windows forms c решение квадратного уравнения
  • Windows forms c возведение в степень
  • Windows forms c visual studio учебник
  • Windows forms c visual studio 2019 уроки
  • Windows forms c visual studio 2010 скачать