Owner Draw Listbox - Performance?

J

James Radke

Hello,

I am creating an owner draw listbox for a windows application. It is all
working, except the performance is significantly slower than the standard
listbox. Basically what I have done is added two new properties (full
source below):

ChangeBackgroundMember = a bound data field which contains a boolean as
to whether this record should get a special background color
ChangeBackgroundColor = the color to use when the above mentioned flag
is set to true

Can someone tell me what I can do to improve the performance of this
modified databound listbox?

Thanks!

======================================== source code
====================================================================

Imports System.Drawing
Imports System.Drawing.Drawing2D

Public Class ColoredListBox
Inherits ListBox

Private _ChangeBackgroundMember As String
Private _ChangeBackgroundColor As Color

Public Property ChangeBackgroundMember() As String
Get
Return _ChangeBackgroundMember
End Get
Set(ByVal Value As String)
_ChangeBackgroundMember = Value
End Set
End Property

Public Property ChangeBackgroundColor() As Color
Get
Return _ChangeBackgroundColor
End Get
Set(ByVal Value As Color)
_ChangeBackgroundColor = Value
End Set
End Property

Private Sub ColoredListBox_DrawItem(ByVal sender As Object, ByVal e As
System.Windows.Forms.DrawItemEventArgs) Handles MyBase.DrawItem
Dim brush As Brush
Dim selected As Boolean
Dim displayText As String

' Get the current data row in the bound datatable
Dim myRow As DataRowView = CType(sender.items(e.Index), DataRowView)

' The following method should generally be called before drawing.
' It is actually superfluous here, since the subsequent drawing
' will completely cover the area of interest.
e.DrawBackground()

'Declare backcolor and forecolor temporary variables
Dim myBackColor As Color
Dim myForeColor As Color

' if the item is selected, then show it as darkblue background with
white text
If (e.State And DrawItemState.Selected) = DrawItemState.Selected
Then
myBackColor = Color.DarkBlue
myForeColor = Color.White
Else
' if the field indicated by the properties is true, then set the
background color to
' the specified color, otherwise use the default background and
foreground colors
If myRow(ChangeBackgroundMember) Then
myBackColor = ChangeBackgroundColor
myForeColor = Color.Black
Else
myBackColor = Me.BackColor
myForeColor = Me.ForeColor
End If
End If
' Create a brush of the background color, and fill the field area
brush = New SolidBrush(myBackColor)
e.Graphics.FillRectangle(brush, e.Bounds)

' Create a brush of the foreground color and draw the text using the
value of the display field
brush = New SolidBrush(myForeColor)
e.Graphics.DrawString(myRow(Me.DisplayMember), Me.Font, brush,
e.Bounds.X, e.Bounds.Y)

e.DrawFocusRectangle()

myRow = Nothing
End Sub
End Class
 
P

Peter Huang

Hi James,

I tested your code on my machine with the Orders table in the Northwind
database.
The performance is just one second on my machine similar with the ListBox.

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
Dim o As DateTime
o = Now
Dim lstbx As ColoredListBox
SqlDataAdapter1.Fill(Me.DataSet31)
lstbx = New ColoredListBox
lstbx.DrawMode = DrawMode.OwnerDrawFixed
Me.Controls.Add(lstbx)
lstbx.DataSource = Me.DataSet31.Orders
lstbx.DisplayMember = "ShipName"
lstbx.ChangeBackgroundMember = "ShipVia"
lstbx.ChangeBackgroundColor = Color.Red
Dim ts As New TimeSpan(Now.Ticks - o.Ticks)
MsgBox(ts.Ticks)
MsgBox(ts.Seconds)
End Sub

In the ColoredListBox, I just change one code line to adapt my test
table(Orders)

If myRow(ChangeBackgroundMember) >= 1 Then

and this will cause the ColoredListBox render about 800 rows of data in
ColoredListBox.

You may create a new project and try my code to see if the problem persist.
My test environment is PIII733, 512MB RAM.
If you have any concern on this issue, please post here.

Regards,
Peter Huang
Microsoft Online Partner Support
Get Secure! www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
J

James Radke

Good Morning Peter,

On my application, I am using the listbox on a sub-form (i.e. modal pop-up).
When the pop up is loaded using the standard listbox, as soon as the page
appears, all data is already showing in the listbox (very fast load). When
I use the ColoredListbox in the pop up in place of the Listbox, the time is
very close using your measuring method to show the pop-up screen; however,
when the page is rendered the listbox does not have any data in it yet, and
it seems to take a couple seconds 3-4 before the data slowly gets rendered
in the listbox and the items appear.

Once it has been created, it appears that the scrolling using the scroll
bars is about the same as the listbox.

What could be causing the delay between when the ColoredListbox is first
presented empty, and the slow actual rendering of the items in the listbox?
Is there another override that I missed that I need to do in my class?

Thanks!

Jim
 
P

Peter Huang

Hi James,

It seems that the performance hit occurs in the ownerdraw function.
You may try to change your code as follows.

Dim brush As SolidBrush
Public Sub New()
MyBase.New()
brush = New SolidBrush(Color.Black)
End Sub

Private Sub ColoredListBox_DrawItem(ByVal sender As Object, ByVal e As
System.Windows.Forms.DrawItemEventArgs) Handles MyBase.DrawItem
Dim selected As Boolean
Dim displayText As String
' Get the current data row in the bound datatable
Dim myRow As DataRowView = CType(sender.items(e.Index), DataRowView)
' The following method should generally be called before drawing.
' It is actually superfluous here, since the subsequent drawing
' will completely cover the area of interest.
e.DrawBackground()
'Declare backcolor and forecolor temporary variables
Dim myBackColor As Color
Dim myForeColor As Color
' if the item is selected, then show it as darkblue background with
white(Text)
If (e.State And DrawItemState.Selected) = DrawItemState.Selected
Then
myBackColor = Color.DarkBlue
myForeColor = Color.White
Else
' if the field indicated by the properties is true, then set
the background color to
' the specified color, otherwise use the default background and
foreground(colors)
If myRow(ChangeBackgroundMember) >= 1 Then
myBackColor = ChangeBackgroundColor
myForeColor = Color.Black
Else
myBackColor = Me.BackColor
myForeColor = Me.ForeColor
End If
End If
' Create a brush of the background color, and fill the field area
brush.Color = myBackColor
e.Graphics.FillRectangle(brush, e.Bounds)
' Create a brush of the foreground color and draw the text using
the value of the display field
brush.Color = myForeColor
e.Graphics.DrawString(myRow(Me.DisplayMember), Me.Font, brush,
e.Bounds.X, e.Bounds.Y)
e.DrawFocusRectangle()
myRow = Nothing
End Sub

You may also try to test with fewer datarow in your coloredlistbox to see
if the problem persists.
I have also tested with a popup form, the render will complete less than
one second after the form is show on about 8000 rows data.
Did the problem occurs when you popup your form with coloredlistbox on the
second time?
(i.e. you click a button will popup the form with coloredlistbox , close
the form and popup it again)
If you have any concern on this issue, please post here.

Regards,
Peter Huang
Microsoft Online Partner Support
Get Secure! www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
J

James Radke

Peter,

The application is working fine now. It seems like if I recompiled the
application as Release versus Debug, many of the performance issues went
away. This type of performance change between release and debug was not
something that I had experienced before.

So, for now, I would say that this is fine!

Thanks for the help!

Jim
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top