ListView & ImageLists

JaedenRuiner

Well-known member
Joined
Aug 13, 2007
Messages
340
Programming Experience
10+
Okay,

Now for the Stupid award going to VB.NET, but I want to do something the darn thing just won't let me...so i'm here to see if there is a way around it.

A ListView, set in constant Details mode, has Three Image Lists: Large, Small, and State. You can have checkboxes, and images. I want checkboxes, not images. This list will not have any images whatsoever. BUT!!! The columns will need an image on the ColumnHeaders in order to indicate a Sort State of that column. Since the ListView does not come default with column specific sorting I wrote my own in my back end Collection, and when it completes resorting my internal list, I repopulate the ListView. Seems to work fine. Except:

VB.NET:
Column1      Column2      Column3
Item1          Item2         Item3
The above is the List without any imagelists set.

VB.NET:
Column1      Column2      Column3
   Ite...      Item2         Item3
This one, is what happens when i define a "smallimagelist" or "largeImagelist". I DO NOT WANT THIS BEHAVIOR. The list items will never have an image associated to them. But in order for the COlumnHeader to have a image on it, I need to have a image list set. And go figure, ColumnHeader.ImageList is a READONLY property.
How do I bypass this stupidity?

Thanks
Jaeden "Sifo Dyas" al'Raec Ruiner
 
Addendum

Okay,
So, on my own, i decide, when you want something done right you do it yourself. It has solved all of these idiotic language barrier issues in the past, such as the sort-by-column issue with the ListView class. (where there is a column click, but the ListView won't sort by column, i'll never know).
However, my issue, is having CheckBox States for each item, but not Image Icon associated to the item, while having image icons associated to the ColumnHeaders. My Solution: Handle the Item State Changing myself, and incorporate the "CheckBox" images into the SmallImagelist, and basing the ImageIndex off of the ListViewItem.Checked property. Here is my code:

VB.NET:
Sub ListViewItemCheck(ByVal sender As Object, ByVal e As ItemCheckEventArgs)
		Dim i As ListViewItem = TaskListView.Items(e.Index)
		Debug.Print("Checking({0}): {1}", i.Name, i.Checked)
		Debug.Print("Value: {0},{1}", e.NewValue, e.CurrentValue)
	End Sub
	
	
	Sub ListViewItemChecked(ByVal sender As Object, ByVal e As ItemCheckedEventArgs)
		e.Item.ImageIndex = Math.Abs(CInt(e.Item.Checked))
		Debug.Print("Checked({0}): {1}", e.Item.Name, e.Item.Checked)
	End Sub

	Sub ListViewItemSelect(ByVal sender As Object, ByVal e As ListViewItemSelectionChangedEventArgs)
		If e.IsSelected then 'AndAlso (f_ClickLocation.X <= 20) AndAlso (f_ClickLocation.X >= 4) Then
			Debug.Print("Select({0}): {1}", e.Item.Name, e.Item.Checked)
		End If		
	End Sub
	
	Sub ListViewMouseClick(ByVal sender As Object, ByVal e As MouseEventArgs)
		Dim lv As ListView = sender
		Dim Idx As Integer = (e.Location.Y \ 17) - 1
		Dim i As ListViewItem = lv.Items(Idx)
		If (e.Location.X >= 4) AndAlso (e.Location.x <= 20) AndAlso (Idx > -1) AndAlso (Idx < lv.Items.Count) Then
			i.Checked = Not i.Checked
		End If
		Debug.Print("Click({0}): {1}", i.Name, i.Checked)
	End Sub

Seems pretty straight forward. When an Item is clicked and the mouse pointer location is within the right range, it toggles the ListViewItem.Checked property. Which, according to LOGIC, would trigger the ItemCheck() event and subsequently the ItemChecked() event which sets the ListViewItem.ImageIndex. If you notice all the Debug.Print() statements, you'll see I recorded the event trigger order to help find out the issues.
these are the results of my test. Each Click event was within the correct range for the item to be Checked, not just selected. (I've provide comments for each one to show the program flow)
VB.NET:
Select(HFHS0035_2008012_Pull): False
Click(HFHS0035_2008012_Pull): True
Checking(HFHS0035_2008012_Pull): True
Value: Unchecked,Checked  //Checked was set to True, so why is the NEWVALUE False???
Checked(HFHS0035_2008012_Pull): False <- I clicked it only once, so this should be true!!!
//I can't even begin to explain why these events fired twice
Checking(HFHS0035_2008012_Pull): False
Value: Checked,Unchecked
Checked(HFHS0035_2008012_Pull): True
Click(HFHS0035_2008012_Pull): True
Select(BHG0032_2007124_Pull): False
Click(BHG0032_2007124_Pull): True
Checking(BHG0032_2007124_Pull): True
Value: Unchecked,Checked  <- Again I set Checked to True, and here it is false
Checked(BHG0032_2007124_Pull): False
Select(SPMH9800_2008012_Pull): False
Click(SPMH9800_2008012_Pull): True  <Where is the Checking/Checked events?
Select(BHG0032_2007124_Pull): False
Checking(BHG0032_2007124_Pull): False
Value: Checked,Unchecked <Checked is set to False, but here it is true
Checked(BHG0032_2007124_Pull): True

Click(BHG0032_2007124_Pull): True
Select(WEL0003_2008012_Pull): False
Click(WEL0003_2008012_Pull): True
Checking(WEL0003_2008012_Pull): True
Value: Unchecked,Checked <Again, I think the component is a little confused
Checked(WEL0003_2008012_Pull): False
Click(WEL0003_2008012_Pull): False <- why is there a secondary click event after 

Select(GHS0050_2008013_Pull): False
Click(GHS0050_2008013_Pull): True
Select(GHS0064_2008012_Pull): False
Click(GHS0064_2008012_Pull): True
Select(UHS9800_2008012_Pull): False
Click(UHS9800_2008012_Pull): True

//The above i clicked in sequence, and you can see I've set the Checked property to true, for each one, and none of them triggered a Checking/Checked event

//I came back to check one already checked, and suddenly the checking/checked events trigger, but the trigger backwards.
Select(GHS0050_2008013_Pull): True
Checking(GHS0050_2008013_Pull): True
Value: Unchecked,Checked
Checked(GHS0050_2008013_Pull): False
Click(GHS0050_2008013_Pull): False

So you can see the assumed order of operation would be:
MouseDown
MouseClick
Select
ItemCheck
ItemChecked
MouseUp

As it appears, I'm something more like this:
MouseDown
Select
MouseClick

And Only when I click a second time in a Item whose Checked Property has been set again, then I get
MouseDown
Select
ItemCheck
ItemChecked
Click()

Well the ItemCheck is happening before the Click() so it is reading the current value as True, and toggling it, and then the click() even happens afterwards and re-toggles the value. The handling of events here is PATHETIC. I write my own code all the time and my events always fire in the sequence they are given, and they fire EVERYTIME. VB.NET is written by the supposed "masters" of language, and their events aren't even reliable that they'll fire. The Checking/Checked events should fire EVERYTIME the Checked property is changed. Not when the ListView feels, on a whim, that okay, i'll fire the event now.

How can this language into doing what it is SUPPOSED to do.

Disgruntled,
Jaeden "Sifo Dyas" al'Raec Ruiner
 
Since the ListView does not come default with column specific sorting I wrote my own in my back end Collection, and when it completes resorting my internal list, I repopulate the ListView.
It does have an easily accessible ListViewItemSorter property, a code sample in documentation that sorts ascending each column click.
However, my issue, is having CheckBox States for each item, but not Image Icon associated to the item, while having image icons associated to the ColumnHeaders. My Solution: Handle the Item State Changing myself, and incorporate the "CheckBox" images into the SmallImagelist, and basing the ImageIndex off of the ListViewItem.Checked property.
VB.NET:
Private Sub listview1_MouseClick(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles listview1.MouseClick
    Dim hti As ListViewHitTestInfo = listview1.HitTest(e.Location)
    If hti.Location = ListViewHitTestLocations.Image Then
        hti.Item.Checked = Not hti.Item.Checked
        hti.Item.ImageIndex = Math.Abs(CInt(hti.Item.Checked))
    End If
End Sub
 
But,
based upon that code, Yes, i am aware I can do it that way, but it somewhat defeats the purpose of having a "Check" and "Checked" event now, doesn't it?
I didn't know about the HitTest() method which is very helpful, as well that i didn't use the list view sorting by column, because my method words cleaner for my back end objects, but for other purposes it is good to know that there is a way to handle sorting other than doing it myself. But when I set Item.Checked = Not Item.Checked, the events ItemCheck() and ItemChecked() should fire 100% of the time, not on the components whim.
To say the least vb is frustrating, and i sometimes curse the decision to be a delphi programmer, instead of a C programmer. learning vb is like pulling teeth. oh well, thanks for the tip, and in the future i'll try to curtail my animosity to illogical logic.
Thanks
Jaeden "Sifo Dyas" al'Raec Ruiner
 
Ack, well another glitch that I thought was superfluous, but now it isn't. I need to read the double click. When I double click the item, whether in the check box or not, i want to do a specific action, so I guess i must put it all in the MouseDown event, because the Click() event never records the double click and it occurs before the MouseDown event can set my globel "doubleclicking" variable i used previously.
 
based upon that code, Yes, i am aware I can do it that way, but it somewhat defeats the purpose of having a "Check" and "Checked" event now, doesn't it?
But when I set Item.Checked = Not Item.Checked, the events ItemCheck() and ItemChecked() should fire 100% of the time, not on the components whim.
These events only work properly if you use the default checkbox functionality, ie when CheckBoxes=True, otherwise ignore them.

Ack, well another glitch that I thought was superfluous, but now it isn't. I need to read the double click. When I double click the item, whether in the check box or not, i want to do a specific action, so I guess i must put it all in the MouseDown event, because the Click() event never records the double click and it occurs before the MouseDown event can set my globel "doubleclicking" variable i used previously.
This is the full event order for a doubleclick by mouse, the documentation for MouseDoubleClick event list this sequence:
MouseDown
Click
MouseClick
MouseUp
MouseDown
DoubleClick
MouseDoubleClick
MouseUp
But you only need the MouseDoubleClick event (or ItemActivate), don't you?
 
Back
Top