ListView: Virtual & OwnerDrawn flicker problem

P

Patrick Wolf

Hi,

I got a challenge with the ListView.

When using the Virtual Mode and OwnerDrawn the images flicker very strongly.
When using the normal mode and OwnerDrawn there is no flicker.

I would need to use the Virtual Mode though :).
Could anybody help (please use the code below as an example).

Thanks very much
Regards
Patrick
www.patrickwolf.net

'-------------------------------------------------------------------------------------------
' To run the code create a new Windows Application project
' Click on show all files
' Delete Form1.Designer.vb
' Click on code view for Form1.vb
' Delete all code and replace with this code here
' Click on run
Public Class Form1
Inherits System.Windows.Forms.Form
#Region "Designer"
Public Sub New()
' This call is required by the Windows Form Designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
End Sub
'Form overrides dispose to clean up the component list.
<System.Diagnostics.DebuggerNonUserCode()> _
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing AndAlso components IsNot Nothing Then
components.Dispose()
End If
MyBase.Dispose(disposing)
End Sub
'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer
'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
<System.Diagnostics.DebuggerStepThrough()> _
Private Sub InitializeComponent()
Me.components = New System.ComponentModel.Container
Me.uxListView1 = New SampleListView
Me.uxListView2 = New SampleListView
Me.SuspendLayout()
'
'uxListView1
'
Me.uxListView1.Anchor = CType((((System.Windows.Forms.AnchorStyles.Top Or
System.Windows.Forms.AnchorStyles.Bottom) _
Or System.Windows.Forms.AnchorStyles.Left) _
Or System.Windows.Forms.AnchorStyles.Right),
System.Windows.Forms.AnchorStyles)
Me.uxListView1.Location = New System.Drawing.Point(12, 12)
Me.uxListView1.Name = "uxListView1"
Me.uxListView1.OwnerDraw = True
Me.uxListView1.Size = New System.Drawing.Size(409, 437)
Me.uxListView1.TabIndex = 0
Me.uxListView1.UseCompatibleStateImageBehavior = False
Me.uxListView1.VirtualListSize = 9
Me.uxListView1.VirtualMode = True
'
'uxListView2
'
Me.uxListView2.Anchor = CType(((System.Windows.Forms.AnchorStyles.Top Or
System.Windows.Forms.AnchorStyles.Bottom) _
Or System.Windows.Forms.AnchorStyles.Right),
System.Windows.Forms.AnchorStyles)
Me.uxListView2.Location = New System.Drawing.Point(437, 12)
Me.uxListView2.Name = "uxListView2"
Me.uxListView2.OwnerDraw = True
Me.uxListView2.Size = New System.Drawing.Size(406, 437)
Me.uxListView2.TabIndex = 1
Me.uxListView2.UseCompatibleStateImageBehavior = False
Me.uxListView2.VirtualListSize = 9
Me.uxListView2.VirtualMode = True
'
'ListViewTest
'
Me.AutoScaleDimensions = New System.Drawing.SizeF(8.0!, 16.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(864, 461)
Me.Controls.Add(Me.uxListView2)
Me.Controls.Add(Me.uxListView1)
Me.Name = "ListViewTest"
Me.Text = "ListViewTest"
Me.ResumeLayout(False)
End Sub
Friend WithEvents uxListView1 As SampleListView
Friend WithEvents uxListView2 As SampleListView
#End Region
Private Sub ListViewTest_Load(ByVal sender As Object, ByVal e As
System.EventArgs) Handles Me.Load
With uxListView1
..VirtualMode = False
For i As Int16 = 0 To 10
..Items.Add(MyListItems.GetListItem(i))
Next
End With
With uxListView2
..VirtualMode = True
..VirtualListSize = 10
End With
End Sub
End Class
Public Class MyListItems
Public Shared Function GetListItem(ByVal index As Integer) As ListViewItem
Return New ListViewItem(index.ToString)
End Function
End Class
' Sample class that derives from the owner-drawn listview control.
Public Class SampleListView
Inherits ListView
' gdi objects used to draw each cell
Private _format As StringFormat
Private _font As Font
Public Sub New()
MyBase.New()
' create gdi objects
_format = New StringFormat
_format.Alignment = StringAlignment.Center
_format.LineAlignment = StringAlignment.Center
_font = New Font("arial", 36, FontStyle.Bold)
' set up image list for thumb size
Me.LargeImageList = New ImageList()
Me.LargeImageList.ImageSize = New Size(100, 100)
' owner drawn
Me.OwnerDraw = True
Me.DoubleBuffered = True
End Sub
Private Sub SampleListView_DrawItem(ByVal sender As Object, ByVal e As
System.Windows.Forms.DrawListViewItemEventArgs) Handles Me.DrawItem
' get the item that needs to be drawn
Dim item As ListViewItem = Me.Items(e.ItemIndex)
Dim g As Graphics = e.Graphics
' bounds for the item
Dim bounds As New RectangleF(item.Bounds.X, item.Bounds.Y, _
item.Bounds.Width, item.Bounds.Height)
' background, could create this brush when the backgroud color
' changes instead of each time
Dim backBrush As New SolidBrush(SystemColors.GradientInactiveCaption)
g.FillRectangle(backBrush, bounds)
' leave a little room
bounds.Inflate(-5, -5)
' use antialias when drawing
g.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias
If item.Selected Then
' selected
g.DrawEllipse(SystemPens.Highlight, bounds)
bounds.Offset(2, 2)
g.DrawString(item.Text, _font, Brushes.DarkGray, bounds, _format)
bounds.Offset(-2, -2)
g.DrawString(item.Text, _font, SystemBrushes.Highlight, bounds, _format)
Else
' not selected
g.DrawEllipse(SystemPens.Control, bounds)
bounds.Offset(2, 2)
g.DrawString(item.Text, _font, SystemBrushes.ControlDark, bounds, _format)
bounds.Offset(-2, -2)
g.DrawString(item.Text, _font, SystemBrushes.Control, bounds, _format)
End If
' cleanup
backBrush.Dispose()
End Sub
Private Sub SampleListView_RetrieveVirtualItem(ByVal sender As
System.Object, ByVal e As System.Windows.Forms.RetrieveVirtualItemEventArgs)
Handles MyBase.RetrieveVirtualItem
e.Item = MyListItems.GetListItem(e.ItemIndex)
End Sub
End Class
'-------------------------------------------------------------------------------------------
 
B

bryan.l.porter

Salutations,

This may have something to do with a problem I've encountered.

It would seem that when the ListView is in VirtualMode, it raises the
RetrieveVirtualItem event for any repaint operation - even one as
simple as resizing a column. This would appear to be a bug (atleast to
my eye), is there anyone at Microsoft that might be able to confirm
this? Is this a bug, or is this by design (and if it is by design, is
there a reason it behaves in this manner?)

Regards,
Bryan Porter
 
P

Patrick Wolf

It would seem that when the ListView is in VirtualMode, it raises the
RetrieveVirtualItem event for any repaint operation - even one as
simple as resizing a column. This would appear to be a bug (atleast to
my eye), is there anyone at Microsoft that might be able to confirm
this? Is this a bug, or is this by design (and if it is by design, is
there a reason it behaves in this manner?)
Yes the RetrieveVirtualItem event gets even continuously called when moving
the mouse over an ownerdrawn ListItem which does seem like a bug.

But so far there has been no feedback
Patrick Wolf
 
P

Patrick Wolf

Hi,
I got a challenge with the ListView.

When using the Virtual Mode and OwnerDrawn the images flicker very
strongly.
When using the normal mode and OwnerDrawn there is no flicker.

I would need to use the Virtual Mode though :).
Could anybody help (please use the code below as an example).

Thanks very much
Regards
Patrick
www.patrickwolf.net

The code had wrong line breaks due to the text format of the posting which
is fixed now (see below).

It would be very helpful if someone could respond to the posting as the
flicker is very strong e.g. it makes the listview in VirtualMode in
connection with OwnerDrawn images unusable.

Thanks a lot
Patrick Wolf

'-------------------------------------------------------------------------------------------
' To run the code create a new Windows Application project
' Click on show all files
' Delete Form1.Designer.vb
' Click on code view for Form1.vb
' Delete all code and replace with this code here
' Click on run
Public Class Form1
Inherits System.Windows.Forms.Form
#Region "Designer"
Public Sub New()
' This call is required by the Windows Form Designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
End Sub
'Form overrides dispose to clean up the component list.
<System.Diagnostics.DebuggerNonUserCode()> _
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing AndAlso components IsNot Nothing Then
components.Dispose()
End If
MyBase.Dispose(disposing)
End Sub
'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer
'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
<System.Diagnostics.DebuggerStepThrough()> _
Private Sub InitializeComponent()
Me.components = New System.ComponentModel.Container
Me.uxListView1 = New SampleListView
Me.uxListView2 = New SampleListView
Me.SuspendLayout()
'
'uxListView1
'
Me.uxListView1.Anchor = CType((((System.Windows.Forms.AnchorStyles.Top Or _
System.Windows.Forms.AnchorStyles.Bottom) _
Or System.Windows.Forms.AnchorStyles.Left) _
Or System.Windows.Forms.AnchorStyles.Right), _
System.Windows.Forms.AnchorStyles)
Me.uxListView1.Location = New System.Drawing.Point(12, 12)
Me.uxListView1.Name = "uxListView1"
Me.uxListView1.OwnerDraw = True
Me.uxListView1.Size = New System.Drawing.Size(409, 437)
Me.uxListView1.TabIndex = 0
Me.uxListView1.UseCompatibleStateImageBehavior = False
Me.uxListView1.VirtualListSize = 9
Me.uxListView1.VirtualMode = True
'
'uxListView2
'
Me.uxListView2.Anchor = CType(((System.Windows.Forms.AnchorStyles.Top Or _
System.Windows.Forms.AnchorStyles.Bottom) _
Or System.Windows.Forms.AnchorStyles.Right), _
System.Windows.Forms.AnchorStyles)
Me.uxListView2.Location = New System.Drawing.Point(437, 12)
Me.uxListView2.Name = "uxListView2"
Me.uxListView2.OwnerDraw = True
Me.uxListView2.Size = New System.Drawing.Size(406, 437)
Me.uxListView2.TabIndex = 1
Me.uxListView2.UseCompatibleStateImageBehavior = False
Me.uxListView2.VirtualListSize = 9
Me.uxListView2.VirtualMode = True
'
'ListViewTest
'
Me.AutoScaleDimensions = New System.Drawing.SizeF(8.0!, 16.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(864, 461)
Me.Controls.Add(Me.uxListView2)
Me.Controls.Add(Me.uxListView1)
Me.Name = "ListViewTest"
Me.Text = "ListViewTest"
Me.ResumeLayout(False)
End Sub
Friend WithEvents uxListView1 As SampleListView
Friend WithEvents uxListView2 As SampleListView
#End Region
Private Sub ListViewTest_Load(ByVal sender As Object, ByVal e As _
System.EventArgs) Handles Me.Load
With uxListView1
..VirtualMode = False
For i As Int16 = 0 To 10
..Items.Add(MyListItems.GetListItem(i))
Next
End With
With uxListView2
..VirtualMode = True
..VirtualListSize = 10
End With
End Sub
End Class
Public Class MyListItems
Public Shared Function GetListItem(ByVal index As Integer) As ListViewItem
Return New ListViewItem(index.ToString)
End Function
End Class
' Sample class that derives from the owner-drawn listview control.
Public Class SampleListView
Inherits ListView
' gdi objects used to draw each cell
Private _format As StringFormat
Private _font As Font
Public Sub New()
MyBase.New()
' create gdi objects
_format = New StringFormat
_format.Alignment = StringAlignment.Center
_format.LineAlignment = StringAlignment.Center
_font = New Font("arial", 36, FontStyle.Bold)
' set up image list for thumb size
Me.LargeImageList = New ImageList()
Me.LargeImageList.ImageSize = New Size(100, 100)
' owner drawn
Me.OwnerDraw = True
Me.DoubleBuffered = True
End Sub
Private Sub SampleListView_DrawItem(ByVal sender As Object, ByVal e As _
System.Windows.Forms.DrawListViewItemEventArgs) Handles Me.DrawItem
' get the item that needs to be drawn
Debug.Write("(DrawItem) ")
Dim item As ListViewItem = Me.Items(e.ItemIndex)
Dim g As Graphics = e.Graphics
' bounds for the item
Dim bounds As New RectangleF(item.Bounds.X, item.Bounds.Y, _
item.Bounds.Width, item.Bounds.Height)
' background, could create this brush when the backgroud color
' changes instead of each time
Dim backBrush As New SolidBrush(SystemColors.GradientInactiveCaption)
g.FillRectangle(backBrush, bounds)
' leave a little room
bounds.Inflate(-5, -5)
' use antialias when drawing
g.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias
If item.Selected Then
' selected
g.DrawEllipse(SystemPens.Highlight, bounds)
bounds.Offset(2, 2)
g.DrawString(item.Text, _font, Brushes.DarkGray, bounds, _format)
bounds.Offset(-2, -2)
g.DrawString(item.Text, _font, SystemBrushes.Highlight, bounds, _format)
Else
' not selected
g.DrawEllipse(SystemPens.Control, bounds)
bounds.Offset(2, 2)
g.DrawString(item.Text, _font, SystemBrushes.ControlDark, bounds, _format)
bounds.Offset(-2, -2)
g.DrawString(item.Text, _font, SystemBrushes.Control, bounds, _format)
End If
' cleanup
backBrush.Dispose()
End Sub
Private Sub SampleListView_RetrieveVirtualItem(ByVal sender As _
System.Object, ByVal e As System.Windows.Forms.RetrieveVirtualItemEventArgs)
_
Handles MyBase.RetrieveVirtualItem
Static counter As Int64 = 0
counter += 1
Debug.WriteLine(String.Format("{0} ({1})", e.ItemIndex, counter))
e.Item = MyListItems.GetListItem(e.ItemIndex)
End Sub
End Class
'-------------------------------------------------------------------------------------------
 

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