By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
435,362 Members | 3,489 Online
Bytes IT Community
Submit an Article
Got Smarts?
Share your bits of IT knowledge by writing an article on Bytes.

Putting Checkboxes in any cell in listview

!NoItAll
100+
P: 296
I needed to put checkboxes in several cells in a listview control. The way the listview control works you can really only have an "official" checkbox in the first cell, and attempts to put them anywhere else are thwarted at just about every turn.
So I developed a simple approach using WingDings. The WingDings font has a checked and unchecked box. In this project I place the unchecked box from WingDings centered in any cell I want a checkbox in, and clicking on the cell will result in toggling between the WingDing checked and unchecked character.
Chr(168) is checked and Chr(254) is unchecked.
(float your mouse over the image below to see the whole thing....)


The trick is to set the font in specific cells to WingDings.
First we have to create a font object:
Expand|Select|Wrap|Line Numbers
  1. Dim myCheckFont As New System.Drawing.Font("Wingdings", 12, FontStyle.Regular)
  2.  
Then we need to assign it to the specific cell in which we want to have a checkbox. You set the font as you create the cells. So in the following example I am creating a table of 16 rows in a listview instantiated with 3 columns. Each time we add an item to column 1 we set the font to MyCheckFont (the WingDings font as assigned above).
Expand|Select|Wrap|Line Numbers
  1.         With ListView1
  2.             For I As Integer = 0 To 15
  3.                 .Items.Add("test" & I.ToString)
  4.                 .Items(I).UseItemStyleForSubItems = False
  5.                 .Items(I).SubItems.Add(Chr(168))
  6.                 .Items(I).SubItems.Item(1).ForeColor = Color.DarkRed
  7.                 .Items(I).SubItems.Item(1).Font = myCheckFont
  8.                 ReDim bOWCheck(I)
  9.             Next I
  10.         End With
  11.  
The trick here is to make sure we set UseItemSylteForSubItems to FALSE. If we do not do that then we can not have separate fonts for different columns. That's a real nice piece of esoterica!
Finaly the only thing you then need to manage is to catch the clicks in the particular column and row so you can then toggle between the two WingDing characters that represent the checked and unchecked boxes.
This too is steeped in some esoteric functionality. Why MS didn't give us a simple way to get the cell that was clicked is beyond me - but they didn't so we have to do it the hard way.
In the listview MouseUp event I have the following code
Expand|Select|Wrap|Line Numbers
  1.     Private Sub ListView1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles ListView1.MouseUp
  2.         Dim cellLoc As MyCell
  3.         cellLoc = WhichCell(ListView1, e.X, e.Y)
  4.         If cellLoc.Col = 2 Then
  5.             If bOWCheck(cellLoc.Row) = True Then
  6.                 ListView1.Items(cellLoc.Row).SubItems(cellLoc.Col - 1).Text = Chr(168)
  7.                 bOWCheck(cellLoc.Row) = False
  8.             Else
  9.                 ListView1.Items(cellLoc.Row).SubItems(cellLoc.Col - 1).Text = Chr(254)
  10.                 bOWCheck(cellLoc.Row) = True
  11.             End If
  12.  
  13.         End If
  14. End Sub
  15.  
Notice the WhichCell function - that's doing the esoteric work...
Expand|Select|Wrap|Line Numbers
  1.     Private Function WhichCell(ByVal lvw As ListView, ByVal X As Integer, ByVal Y As Integer) As MyCell
  2.  
  3.         Dim colstart As Integer = 0
  4.         Dim colend As Integer = 0
  5.         Dim xCol As Integer
  6.  
  7.         For xCol = 0 To (ListView1.Columns.Count - 1)
  8.             colend = colend + ListView1.Columns(xCol).Width
  9.             If colstart <= X And X <= colend Then
  10.                 WhichCell.Col = xCol + 1
  11.                 Exit For
  12.             End If
  13.             colstart = colstart + ListView1.Columns(xCol).Width
  14.         Next
  15.  
  16.         WhichCell.Row = ListView1.FocusedItem.Index
  17.         Return WhichCell
  18.  
  19.     End Function
  20.  
Finally - to keep track of the checkboxes I have a boolean array: bOWCheck() that I index to the current row. If you have multiple column just add another dimension to the array. This is where we persist the state of the checkbox for each cell. Notice it is toggled in the listview MouseUp event along with toggling the WingDing checked and unchecked characters.

There are possibly several better ways to do this. Improvements are certainly welcome.
I've attached a zip file with a VS2008 VB.NET project you can play with.
Attached Files
File Type: zip lstViewChecks.zip (69.0 KB, 3453 views)
Jan 21 '10 #1
Share this Article
Share on Google+
5 Comments


P: 1
This is a really neat trick. Well done for working it out and sharing.
Jan 29 '15 #2

P: 2
Just came across this, and was exactly what I was looking for. Very clever and easy to implement. Thanks for posting this!
Feb 10 '19 #3

IronRazer
P: 82
Kind of handy if you really want to use a ListView but, it is much easier to just use a DataGridView which can be made to look just like a ListView and can easily have a checkbox column on any column(s) you want. 8)
Feb 11 '19 #4

!NoItAll
100+
P: 296
It's been a long time since I wrote this post. There was a reason I didn't use the dataGridView at the time. It might not have been a good reason - but it was a reason... ;-)
Feb 11 '19 #5

P: 2
Hey guys - I am aware that a DataGridView could be used, and in fact use that quite a bit. The reason this came in handy is that I had an existing ListView and needed to add checkbox columns to it "after the fact". Rather than rewriting that part of the interface from scratch with the DGV, it was quite handy to add these checkbox columns to the existing LV.
Feb 11 '19 #6