W
Wiktor Zychla
today we've found a critical issue regarding the ListView from
Windows.Forms. it was confirmed on several machines with Win2K and XP.
here's the problem: create a ListView with about 50000 rows. now use task
manager to see the GDI usage of the process. everything seems normal.
now catch the ListView's scroller and start to move it downwards. you have
to hold the constant speed so that the ListView is constantly repainted.
look at the GDI usage of the application. it starts to increase, starting at
21 and going through 1000-5000. if you get the bottom of the ListView,
immediately start to scroll it upwards so that the ListView is constantly
repainted. you'll see that the GDI objects count reaches the 10000 and then
jumps to over 4297000000! remember to keep the scrolling speed!
running from the IDE can even make the Windows GDI subsystem completely
broken and hang the whole system (this is what our application does when it
is misused!).
here's the simple code. compile it, press the button "button 1" and watch
the GDI usage.
in the attachment I've included the snapshot of the Task Manager showing the
GDI usage. I am really desperate to hear from anyone about that. could
anyone confirm the problem or point my mistake?
Regards,
Wiktor
-----------------------------------------------------
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
namespace vicTestF
{
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.ListView listView1;
private System.Windows.Forms.ColumnHeader columnHeader1;
private System.Windows.Forms.ColumnHeader columnHeader2;
private System.Windows.Forms.ColumnHeader columnHeader3;
private System.Windows.Forms.Button button1;
private System.ComponentModel.Container components = null;
public Form1()
{
InitializeComponent();
}
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
private void InitializeComponent()
{
this.listView1 = new System.Windows.Forms.ListView();
this.columnHeader1 = new System.Windows.Forms.ColumnHeader();
this.columnHeader2 = new System.Windows.Forms.ColumnHeader();
this.columnHeader3 = new System.Windows.Forms.ColumnHeader();
this.button1 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// listView1
//
this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.columnHeader1,
this.columnHeader2,
this.columnHeader3});
this.listView1.Dock = System.Windows.Forms.DockStyle.Fill;
this.listView1.GridLines = true;
this.listView1.Location = new System.Drawing.Point(0, 32);
this.listView1.Name = "listView1";
this.listView1.Size = new System.Drawing.Size(496, 289);
this.listView1.TabIndex = 0;
this.listView1.View = System.Windows.Forms.View.Details;
//
// columnHeader1
//
this.columnHeader1.Width = 143;
//
// columnHeader2
//
this.columnHeader2.Width = 115;
//
// columnHeader3
//
this.columnHeader3.Width = 229;
//
// button1
//
this.button1.Dock = System.Windows.Forms.DockStyle.Top;
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(496, 32);
this.button1.TabIndex = 1;
this.button1.Text = "button1";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(496, 321);
this.Controls.AddRange(new System.Windows.Forms.Control[] {
this.listView1,
this.button1});
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
}
#endregion
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
private void button1_Click(object sender, System.EventArgs e)
{
listView1.BeginUpdate();
ListViewItem li;
for ( int i=0; i<50000; i++ )
{
// ListViewItem li = listView1.Items.Add( "item" + i.ToString() );
li = listView1.Items.Add( "item" + i.ToString() );
li.SubItems.Add( "qwer" );
li.SubItems.Add( "qwer" );
}
MessageBox.Show( "before endupdate" );
listView1.EndUpdate();
}
}
}
Windows.Forms. it was confirmed on several machines with Win2K and XP.
here's the problem: create a ListView with about 50000 rows. now use task
manager to see the GDI usage of the process. everything seems normal.
now catch the ListView's scroller and start to move it downwards. you have
to hold the constant speed so that the ListView is constantly repainted.
look at the GDI usage of the application. it starts to increase, starting at
21 and going through 1000-5000. if you get the bottom of the ListView,
immediately start to scroll it upwards so that the ListView is constantly
repainted. you'll see that the GDI objects count reaches the 10000 and then
jumps to over 4297000000! remember to keep the scrolling speed!
running from the IDE can even make the Windows GDI subsystem completely
broken and hang the whole system (this is what our application does when it
is misused!).
here's the simple code. compile it, press the button "button 1" and watch
the GDI usage.
in the attachment I've included the snapshot of the Task Manager showing the
GDI usage. I am really desperate to hear from anyone about that. could
anyone confirm the problem or point my mistake?
Regards,
Wiktor
-----------------------------------------------------
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
namespace vicTestF
{
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.ListView listView1;
private System.Windows.Forms.ColumnHeader columnHeader1;
private System.Windows.Forms.ColumnHeader columnHeader2;
private System.Windows.Forms.ColumnHeader columnHeader3;
private System.Windows.Forms.Button button1;
private System.ComponentModel.Container components = null;
public Form1()
{
InitializeComponent();
}
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
private void InitializeComponent()
{
this.listView1 = new System.Windows.Forms.ListView();
this.columnHeader1 = new System.Windows.Forms.ColumnHeader();
this.columnHeader2 = new System.Windows.Forms.ColumnHeader();
this.columnHeader3 = new System.Windows.Forms.ColumnHeader();
this.button1 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// listView1
//
this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.columnHeader1,
this.columnHeader2,
this.columnHeader3});
this.listView1.Dock = System.Windows.Forms.DockStyle.Fill;
this.listView1.GridLines = true;
this.listView1.Location = new System.Drawing.Point(0, 32);
this.listView1.Name = "listView1";
this.listView1.Size = new System.Drawing.Size(496, 289);
this.listView1.TabIndex = 0;
this.listView1.View = System.Windows.Forms.View.Details;
//
// columnHeader1
//
this.columnHeader1.Width = 143;
//
// columnHeader2
//
this.columnHeader2.Width = 115;
//
// columnHeader3
//
this.columnHeader3.Width = 229;
//
// button1
//
this.button1.Dock = System.Windows.Forms.DockStyle.Top;
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(496, 32);
this.button1.TabIndex = 1;
this.button1.Text = "button1";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(496, 321);
this.Controls.AddRange(new System.Windows.Forms.Control[] {
this.listView1,
this.button1});
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
}
#endregion
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
private void button1_Click(object sender, System.EventArgs e)
{
listView1.BeginUpdate();
ListViewItem li;
for ( int i=0; i<50000; i++ )
{
// ListViewItem li = listView1.Items.Add( "item" + i.ToString() );
li = listView1.Items.Add( "item" + i.ToString() );
li.SubItems.Add( "qwer" );
li.SubItems.Add( "qwer" );
}
MessageBox.Show( "before endupdate" );
listView1.EndUpdate();
}
}
}