Answered by:
How do I override a ListViews selected item color

Question
-
As you know, when you load items into a ListView that has it's .view property set to Details, and it's FullRowSelect property set to True, the selected row is highlighted when you click on it.
By default the highlight color is a dark blue.
I want to change it to whatever color I choose.
If I wanted to update each item as I arrow keyed my way through the rows I'd have to write a complicated routine to handle the key presses and update the position of the hightlight color.
Even then I think the new color would be overridden by the default or system color.
My question is How do I change the default highlight color on a ListView control that has it's .View set to Details, and it's FullRowSelect set to True?Saturday, February 28, 2009 2:11 AM
Answers
-
With owner draw you have to do all the drawing that includes the text . You would do that in the DrawSubitem event handler .
Private Sub listView1_DrawSubItem(ByVal sender As Object, _ ByVal e As DrawListViewSubItemEventArgs) _ Handles ListView1.DrawSubItem Dim sf As New StringFormat() Try ' Store the column text alignment, letting it default ' to Left if it has not been set to Center or Right. Select Case e.Header.TextAlign Case HorizontalAlignment.Center sf.Alignment = StringAlignment.Center Case HorizontalAlignment.Right sf.Alignment = StringAlignment.Far End Select e.Graphics.DrawString(e.SubItem.Text, _ Me.ListView1.Font, Brushes.Black, e.Bounds, sf) Finally sf.Dispose() End Try End Sub
Coding for fun- Edited by bdbodger Sunday, March 1, 2009 1:26 AM
- Marked as answer by ThisDisplayNameHasGotToWorkBecauseIBluuBlaaaHa Sunday, March 1, 2009 1:55 AM
Sunday, March 1, 2009 1:20 AM
All replies
-
Saturday, February 28, 2009 2:50 AM
-
bdbodger said:Thanks for the link, it's interesting.
Coding for fun
I can't get that approach to work with a ListView though.
I'm not sure how to set up the class, because I don't know if the backcolor is readonly, or something else.
Even if I did I don't think I could write the class or procedure correctly, because it's beyond the scope of my Visual Basic knowledge.
It seems that it would be as simply as ListView1.FocusedItem.BackColor = Color.Coral
Unfortunately it's not at all that simple, and there is no place on the planet that I know of where I can find the information I need to form a strategy for tackling this task.Saturday, February 28, 2009 3:46 AM -
Does anyone have a clue as to how to set this property?
Anyone?
Saturday, February 28, 2009 4:12 AM -
Sorry that was the wrong link I don't know what I was thinking :-) this is the right link
http://social.msdn.microsoft.com/Forums/en-US/Vsexpressvb/thread/dc4a374f-e2c7-4dbd-8e09-835f36e3e803
Coding for funSaturday, February 28, 2009 5:00 AM -
bdbodger said:
Sorry that was the wrong link I don't know what I was thinking :-) this is the right link
http://social.msdn.microsoft.com/Forums/en-US/Vsexpressvb/thread/dc4a374f-e2c7-4dbd-8e09-835f36e3e803
Coding for fun
I tried that, it didn't do anything.
Well, it threw a few errors, then I removed the part that was looking for 0 currency values and my program ran, but there was no noticeable affect.
I don't understand why something as simple as changing the background color of a selected row in a detail view would require more code than there is in my entire program.Saturday, February 28, 2009 5:53 AM -
Did you set the Listview owner draw property to true ? I know it works you just have to set that property , use detail view and handle the DrawItem event the DrawSubItem event and DrawColumnHeader events . This code changes the selected item background color to maroon . If the item is not selected then the background color will be a gradient .
Private Sub listView1_DrawItem(ByVal sender As Object, _ ByVal e As DrawListViewItemEventArgs) _ Handles listView1.DrawItem If Not (e.State And ListViewItemStates.Selected) = 0 Then ' Draw the background for a selected item. e.Graphics.FillRectangle(Brushes.Maroon, e.Bounds) e.DrawFocusRectangle() Else ' Draw the background for an unselected item. Dim brush As New LinearGradientBrush(e.Bounds, Color.Orange, _ Color.Maroon, LinearGradientMode.Horizontal) Try e.Graphics.FillRectangle(brush, e.Bounds) Finally brush.Dispose() End Try End If ' Draw the item text for views other than the Details view. If Not Me.listView1.View = View.Details Then e.DrawText() End If End Sub
Coding for funSaturday, February 28, 2009 6:16 AM -
Use this at the top of your form so the gradiantbrush does not give you an error
Imports
System.Drawing.Drawing2D
and don't forget that the built in formater in the forum does not show the underscore so the code is like this in reality
Private Sub listView1_DrawItem(ByVal sender As Object, _
ByVal e As DrawListViewItemEventArgs) _
Handles ListView1.DrawItem If Not (e.State And ListViewItemStates.Selected) = 0 Then ' Draw the background for a selected item.e.Graphics.FillRectangle(Brushes.Maroon, e.Bounds)
e.DrawFocusRectangle()
Else ' Draw the background for an unselected item. Dim brush As New LinearGradientBrush(e.Bounds, Color.Orange, _
Color.Maroon, LinearGradientMode.Horizontal) Trye.Graphics.FillRectangle(brush, e.Bounds)
Finallybrush.Dispose()
End Try End If ' Draw the item text for views other than the Details view. If Not Me.ListView1.View = View.Details Thene.DrawText()
End If End Sub
Coding for fun- Edited by bdbodger Saturday, February 28, 2009 6:33 AM
Saturday, February 28, 2009 6:29 AM -
bdbodger said:Warning 1 WithEvents variable 'Location' conflicts with property 'Location' in the base class 'Form' and should be declared 'Shadows'.
Did you set the Listview owner draw property to true ? I know it works you just have to set that property , use detail view and handle the DrawItem event the DrawSubItem event and DrawColumnHeader events . This code changes the selected item background color to maroon . If the item is not selected then the background color will be a gradient .
Private Sub listView1_DrawItem(ByVal sender As Object, _ ByVal e As DrawListViewItemEventArgs) _ Handles listView1.DrawItem If Not (e.State And ListViewItemStates.Selected) = 0 Then ' Draw the background for a selected item. e.Graphics.FillRectangle(Brushes.Maroon, e.Bounds) e.DrawFocusRectangle() Else ' Draw the background for an unselected item. Dim brush As New LinearGradientBrush(e.Bounds, Color.Orange, _ Color.Maroon, LinearGradientMode.Horizontal) Try e.Graphics.FillRectangle(brush, e.Bounds) Finally brush.Dispose() End Try End If ' Draw the item text for views other than the Details view. If Not Me.listView1.View = View.Details Then e.DrawText() End If End Sub
Coding for fun
Error 2 Type 'LinearGradientBrush' is not defined.Saturday, February 28, 2009 6:42 AM -
bdbodger said:
Use this at the top of your form so the gradiantbrush does not give you an error
Imports System.Drawing.Drawing2D
and don't forget that the built in formater in the forum does not show the underscore so the code is like this in reality
Private Sub listView1_DrawItem(ByVal sender As Object, _
ByVal e As DrawListViewItemEventArgs) _
Handles ListView1.DrawItemIf Not (e.State And ListViewItemStates.Selected) = 0 Then
' Draw the background for a selected item.
e.Graphics.FillRectangle(Brushes.Maroon, e.Bounds)
e.DrawFocusRectangle()
Else
' Draw the background for an unselected item.
Dim brush As New LinearGradientBrush(e.Bounds, Color.Orange, _
Color.Maroon, LinearGradientMode.Horizontal)Try
e.Graphics.FillRectangle(brush, e.Bounds)
Finally
brush.Dispose()
End Try
End If
' Draw the item text for views other than the Details view.
If Not Me.ListView1.View = View.Details Then
e.DrawText()
End If
End Sub
Coding for fun
Holy $#|@!
It looks like Tetris!
There's not data in it, and when I first move the mouse over it the grid disappears.
Saturday, February 28, 2009 6:49 AM -
Now I have text in the first row, but it's in Chinese. :-{
Lol
That works to change the BackColor of the selected item. Thanks
Is it possible to do that in the GotFocus event?
Also, is it possible to Change the BackColor in the GotFocus event, and retain the text I've loaded into the ListView?
Saturday, February 28, 2009 7:05 AM -
What the heck are you doing ? Your not doing a wpf project are you ? This is a very simple thing .
Coding for funSaturday, February 28, 2009 3:19 PM -
bdbodger said:
What the heck are you doing ? Your not doing a wpf project are you ? This is a very simple thing .
Coding for fun
No I'm doing a WFA.
It is simple to change the background color, it only takes a line of code.
I can't get it to display the data that I'm loading from file now.
Mainly due to the fact that now I don't know which events to use.
It's like this brush thing is causing VB to behave differently. Or maybe I'm doing something the wrong way.
I don't know.
Am I supposed to drop the ListView onto my Form and then assign it's properties in code, or should I create the entire ListView from code?Saturday, February 28, 2009 4:06 PM -
Now I'm confused.
What seemed like a simple task is look more like a two week detour.
Although I have found a way to change the default hightlight color of a selected item in the ListView(Thanks bdbodger). Now I can't load my file into the ListView.
I'm at a decision point, of whether to continue to pursue this, or to drop it and continue on with the rest of the project.
I guess aesthetics aren't that important. Not as important as being able to display data anyways!
It seems like such a simple task, if only it were as it seems.
Saturday, February 28, 2009 11:29 PM -
With owner draw you have to do all the drawing that includes the text . You would do that in the DrawSubitem event handler .
Private Sub listView1_DrawSubItem(ByVal sender As Object, _ ByVal e As DrawListViewSubItemEventArgs) _ Handles ListView1.DrawSubItem Dim sf As New StringFormat() Try ' Store the column text alignment, letting it default ' to Left if it has not been set to Center or Right. Select Case e.Header.TextAlign Case HorizontalAlignment.Center sf.Alignment = StringAlignment.Center Case HorizontalAlignment.Right sf.Alignment = StringAlignment.Far End Select e.Graphics.DrawString(e.SubItem.Text, _ Me.ListView1.Font, Brushes.Black, e.Bounds, sf) Finally sf.Dispose() End Try End Sub
Coding for fun- Edited by bdbodger Sunday, March 1, 2009 1:26 AM
- Marked as answer by ThisDisplayNameHasGotToWorkBecauseIBluuBlaaaHa Sunday, March 1, 2009 1:55 AM
Sunday, March 1, 2009 1:20 AM -
First off, that's just completely and utterly awesome! Because it works!!!
The DrawSubItems event, that's starting to make some sense.
And second,
This is a new term for me StringFormat()
What is it, and why do we use it?
And third......Awesome!!!
Well except for the fact that I can't see my header text. Probably because I haven't created any except for the ones I set in the Columns Collection in Properties grid.
Anyway,
Why can't I find any of this stuff in my books or anywhere else?
I guess it's more intuitive if you think about it in Event Driven terms.
Sunday, March 1, 2009 1:50 AM -
Add this too
' Forces each row to repaint itself the first time the mouse moves over ' it, compensating for an extra DrawItem event sent by the wrapped ' Win32 control. Private Sub listView1_MouseMove(ByVal sender As Object, _ ByVal e As MouseEventArgs) _ Handles listView1.MouseMove Dim item As ListViewItem = listView1.GetItemAt(e.X, e.Y) If Not item Is Nothing AndAlso item.Tag Is Nothing Then listView1.Invalidate(item.Bounds) item.Tag = "tagged" End If
Coding for funSunday, March 1, 2009 1:56 AM -
bdbodger said:What do this do?
Add this too
' Forces each row to repaint itself the first time the mouse moves over ' it, compensating for an extra DrawItem event sent by the wrapped ' Win32 control. Private Sub listView1_MouseMove(ByVal sender As Object, _ ByVal e As MouseEventArgs) _ Handles listView1.MouseMove Dim item As ListViewItem = listView1.GetItemAt(e.X, e.Y) If Not item Is Nothing AndAlso item.Tag Is Nothing Then listView1.Invalidate(item.Bounds) item.Tag = "tagged" End If
Coding for fun
I know it's commented that it forces each row to repaint it's self, but I don't understand why I would want to do that.Sunday, March 1, 2009 1:59 AM -
StringFormat is for drawing mainly or formating type this
Dim sf As New StringFormat()
then type sf. and let intellesence show you the options or type
sf.FormatFlags =
And see what options popup that will give you an idea of what it does .
Coding for funSunday, March 1, 2009 2:01 AM -
ThisDisplayNameHasGotToWorkBecauseIBluuBlaaaHa said:bdbodger said:What do this do?
Add this too
' Forces each row to repaint itself the first time the mouse moves over ' it, compensating for an extra DrawItem event sent by the wrapped ' Win32 control. Private Sub listView1_MouseMove(ByVal sender As Object, _ ByVal e As MouseEventArgs) _ Handles listView1.MouseMove Dim item As ListViewItem = listView1.GetItemAt(e.X, e.Y) If Not item Is Nothing AndAlso item.Tag Is Nothing Then listView1.Invalidate(item.Bounds) item.Tag = "tagged" End If
Coding for fun
I know it's commented that it forces each row to repaint it's self, but I don't understand why I would want to do that.
Without it when you mouse over a line the first time the line goes blank for some reason I don't know much more than that .
Coding for funSunday, March 1, 2009 2:02 AM -
Remember too that since your doing all the drawing then you can do what you want drawline drawstring drawelipse drawimage drawrectangle those are some of the drawing commands that can be used with e.graphics if you have done any drawing on a form then you already know how to use those .
Coding for funSunday, March 1, 2009 2:08 AM -
bdbodger said:Mine aren't going blank, but I did notice that in the first column the text gets a little darker when I mouseover it, almost bold compared to the way it was when it loaded.ThisDisplayNameHasGotToWorkBecauseIBluuBlaaaHa said:bdbodger said:What do this do?
Add this too
' Forces each row to repaint itself the first time the mouse moves over ' it, compensating for an extra DrawItem event sent by the wrapped ' Win32 control. Private Sub listView1_MouseMove(ByVal sender As Object, _ ByVal e As MouseEventArgs) _ Handles listView1.MouseMove Dim item As ListViewItem = listView1.GetItemAt(e.X, e.Y) If Not item Is Nothing AndAlso item.Tag Is Nothing Then listView1.Invalidate(item.Bounds) item.Tag = "tagged" End If
Coding for fun
I know it's commented that it forces each row to repaint it's self, but I don't understand why I would want to do that.
Without it when you mouse over a line the first time the line goes blank for some reason I don't know much more than that .
Coding for fun
I'll see it that last piece of code stops that.Sunday, March 1, 2009 2:08 AM -
bdbodger said:
Remember too that since your doing all the drawing then you can do what you want drawline drawstring drawelipse drawimage drawrectangle those are some of the drawing commands that can be used with e.graphics if you have done any drawing on a form then you already know how to use those .
Coding for fun
O.K. lol, now I know why I couldn't find any of this in my books.
I skipped the section on Graphics, because I thought it wasn't as important just now as getting the file and data aspects handled.
Anyway,
I added that last bit of code, and it mostly stopped the text darkening. There is maybe a very slight flicker in the text it's self, almost not even noticeable.
I actually didn't even notice it darkening before, until you mentioned the lines blanking out, and I started looking closer.
Sunday, March 1, 2009 2:17 AM -
There is a shortcut if your not doing anything special with the text
e.DrawText()
End Sub
Coding for fun- Edited by bdbodger Sunday, March 1, 2009 2:27 AM
Sunday, March 1, 2009 2:26 AM -
I got the headers back, by adding this code. It's actually an example from the documentation.
I only had to change the font to my liking.Private Sub ListView1_DrawColumnHeader(ByVal sender As Object, ByVal e As System.Windows.Forms.DrawListViewColumnHeaderEventArgs) Handles ListView1.DrawColumnHeader Dim sf As New StringFormat() Try ' Store the column text alignment, letting it default ' to Left if it has not been set to Center or Right. Select Case e.Header.TextAlign Case HorizontalAlignment.Center sf.Alignment = StringAlignment.Center Case HorizontalAlignment.Right sf.Alignment = StringAlignment.Far End Select ' Draw the standard header background. e.DrawBackground() ' Draw the header text. Dim headerFont As New Font("Verdana", 10, FontStyle.Regular) Try e.Graphics.DrawString(e.Header.Text, headerFont, _ Brushes.Black, e.Bounds, sf) Finally headerFont.Dispose() End Try Finally sf.Dispose() End Try End Sub
Sunday, March 1, 2009 3:44 AM -
Here's something that got me thinking.
It's the description for OwnerDraw.
"Gets or sets a value indicating whether the ListView control is drawn by the operating system or by code that you provide".
What I'm doing is, I added the ListView from the ToolBox.
Then I added Columns to the Columns Collection in the Properties grid.
Then I added in the Form Load event ListView1.OwnerDraw = True, and added the Graphics code to set the BackColor, and DrawItem, DrawSubItem, and DrawColumnHeader events.
So I'm not actually drawing the entire thing.
I'm just adding some code to change the BackColor of the selected item, which causes the ColumnHeaders, and the Column text to not display.
Then I'm adding more code to make what's already in the ColumnHeaders, and the Columns visible again.
I know this, because I didn't add any columns in my code, or make any changes to the way the data is loaded, what's showing in the headers is set in the properties grid, and the data is loaded in a MenuItem's click event by means of an OpenFileDialog.Sunday, March 1, 2009 3:54 AM -
Yes you can set the OwnerDraw property in the property grid as well but from code is ok . With OwnerDraw you draw the items but the layout is set you just changeing the colors and fonts etc . Your code can be more complex with OwnerDraw like the colors of the text . Given the right code each letter of the text can be a different color . You can draw lines pictures arcs circles etc . That is what they mean by OwnerDraw your not actually laying out the layout just drawing the background and text and what ever else you draw in the "bounds" of the item or subitem . Glad you figured out the header code . Those 3 events are all you need to use . The headers have a text property your just drawing it as do the items and subitems . OwnerDraw does not change the properties of them it just lets you draw them . You can do with it what you want . Want a nice red border around your header item then use drawrectangle in your code . Want the second header to have a different border color then do that too . Have fun with it . Doing it this way allows you to use gradients , that you can't do without OwnerDraw .
Coding for fun- Edited by bdbodger Sunday, March 1, 2009 4:37 AM
Sunday, March 1, 2009 4:34 AM