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
1,9802 gold badges34 silver badges41 bronze badges
asked May 11, 2012 at 14:28
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
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.Emptystring.Empty
10.2k4 gold badges42 silver badges67 bronze badges
- Remove From My Forums
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
__________________
0 |
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 16746 / 12498 / 3285 Регистрация: 17.09.2011 Сообщений: 20,732 |
||||
18.12.2013, 13:06 |
4 |
|||
Подпишитесь на событие списка ItemCheck и в обработчике пропишите такой код:
1 |
moverast 6 / 8 / 0 Регистрация: 30.04.2011 Сообщений: 188 |
||||
18.12.2013, 13:13 [ТС] |
5 |
|||
Что-то Ваш код не осилил. Сделал так:
4 |
Последнее обновление: 31.10.2015
Элемент CheckedListBox представляет симбиоз компонентов ListBox и CheckBox. Для каждого элемента такого списка определено специальное поле CheckBox,
которое можно отметить.
Все элементы задаются в CheckedListBox задаются в свойстве Items. Также, как и для элементов ListBox и
ComboBox, мы можем задать набор элементов. По умолчанию для каждого добавляемого нового элемента флажок не отмечен:
Чтобы поставить отметку в checkBox рядом с элементом в списке, нам надо сначала выделить элемент и дополнительным щелчком уже установить
флажок. Однако это не всегда удобно, и с помощью свойства CheckOnClick и установке для него значения true
мы
можем определить сразу выбор элемента и установку для него флажка в один клик.
Другое свойство MultiColumn при значении true
позволяет сделать многоколоночный список, если элементы
не помещаются по длине:
Выделенный элемент мы также можем получить с помощью свойства 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);
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
15.1k13 gold badges104 silver badges120 bronze badges
asked Mar 10, 2011 at 8:07
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 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
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
7,4232 gold badges28 silver badges42 bronze badges
answered Jan 13, 2014 at 18:45
«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
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
15.1k13 gold badges104 silver badges120 bronze badges
asked Mar 10, 2011 at 8:07
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 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
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
7,4232 gold badges28 silver badges42 bronze badges
answered Jan 13, 2014 at 18:45
«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
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
FunctionToString()
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
NewSqlConnection
With
{.ConnectionString = ConnectionString}
Using cmd
As
NewSqlCommand
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
StringIn
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
NewSqlConnection
With
{.ConnectionString = ConnectionString}
Using cmd
As
NewSqlCommand
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 элементы списка можно выделять цветом, кроме того их можно помечать галочкой.
В отличии от обычного списка, выделить в списке можно только один элемент. Помеченных галочкой элементов может быть несколько.
Выделенный элемент не обязательно должен быть помеченным элементом. За то, следует ли переключать флажок, когда выделяется элемент, отвечает свойство CheckOnClick. По умолчанию свойство имеет значение False и при выделении элемента флажок не переключается. В этом случае, чтобы переключить флажок, нужно выполнить щелчок в области флажка.
Проект «Головоломка «
Головоломка, которую мы решаем. Из заданного набора чисел надо выбрать те, сумма которых составит 50. Числа такие:
25, 27, 3, 12, 6, 15, 9, 30. 21. 19.
Несмотря на кажущуюся простоту, головоломка может доставить немало хлопот.
Какие элементы управления нам понадобятся?
Во-первых, мы используем список флажков. Он похож на обычный список, но возле каждого пункта имеется флажок. Его можно установить или сбросить.
Еще нам понадобится обычный список, без флажков. В него мы поместим выбранные числа. Сумму этих чисел покажем в виде надписи. Окно нашей программы должно выглядеть примерно так, как показано на рисунке.
Технология выполнения
-
- Запустите систему Visual Basic и создайте новый проект под именем Головоломка.
- Установите на форме элементы управления в соответствии с образцом. Мы уже решили, что нам нужны три элемента управления: список флажков (CheckedListBox), простой список (ListBox) и надпись (Label).
- Настройте свойства объектов в соответствии с таблицей:
Объект Свойства Значения Примечание Form1 Text «Головоломка» CheckedListBox Text пусто Items 25, 27, 3, 12, 6, 15, 9, 30, 21, 19 Щелкните в значении свойства Items (Коллекция), на многоточии, появится окно Редактор коллекции строк. Введите числа по одному в строке. ListBox1 Text Пусто Label Text «Сумма: 0» Начальное значение суммы выбранных чисел (пока ничего не выбрано). Alignment MiddleCenter Выравнивание
по центруОкно программы готово и можно приступить к программированию.
- Установка и сброс флажков. В окне программы только один элемент управления способен к диалогу – это список флажков. Программа должна что-то делать только в том случае, если дин из флажков устанавливается или сбрасывается. В этом случае возникает событие 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. - Теперь наша программа умеет правильно реагировать на установку или сброс флажка в списке.
- Обновление суммы. Итак, списки обновлены. Теперь надо заново подсчитать сумму выбранных чисел. Здесь нас ждет небольшой подводный камень. Хотя элементы списка выглядят как числа, они, на самом деле, являются текстовыми строками. Поэтому при суммировании нам придется воспользоваться функцией Val().Это тоже удобно сделать в цикле. Пусть сумма накапливается в переменной S. Ее расчет можно выполнить так:
s = 0 For i = 0 To ListBox1.Items.Count - 1 s = s + Val(ListBox1.Items(i)) Next i
- Чтобы представить вычисленную сумму в поле надписи , она должна быть текстовой строкой. Поэтому преобразовали ее в текстовый тип с помощью функции STR(). Присоединим ее к тексту подсказки с помощью операции слияния строк:
Label1.Text = "Сумма: " + Str(s)
- Проверка решения. Осталось сделать последний шаг: проверить, решена ли головоломка. Так как значение суммы выбранных чисел у нас уже есть, надо сравнить его с заданным числом 50:
If S = 50 Then
- Если головоломка еще не решена, делать ничего не надо и решение можно продолжить. Если же решение найдено, давайте отключим все элементы управления (изменим свойство Enabled) Кроме того, выведем в поле надписи сообщение «Победа». Это можно сделать так:
If s = 50 Then Label1.Text = "Победа: " + Str(s) ListBox1.Enabled = False CheckedListBox1.Enabled = False End If
- Программа готова. На этом наша программа готова, и ее можно испытать. Полный ее текст, как он виден в окне кода, написан ниже.
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
- Нажмите клавишу F5, чтобы запустить программу. При установке флажков выбранные числа попадают во второй список, а при сбросе – удаляются из него.
- Когда программа заработает, попробуйте решить головоломку. Это далеко не самая сложная из головоломок Лойда. На всякий случай примите подсказку: чтобы получить сумму 50, надо выбрать три числа.
В этом уроке мы познакомились с элементом управления CheckedListBox (Список флажков), узнали, как обрабатывать в программном коде установку флажков пользователем. Поработали с обычным списком без флажков ListBox, производили в нем поиск, добавление и удаление записей, суммирование записей.
До встречи в следующем уроке.