Controls.Clear and Controls.Add very slow

S

Shane

I have an application that creates "screens" on the fly via a panel on
a form that I add and remove controls from.

When the user wants to go to a new screen I call
panel.Controls.Clear() and this depending on the number of controls in
the array takes about 40 milliseconds per control! Adding new
controls to it taks about 5-20 ms per controls. When you have 20
controls (labels, and data collection fields) on each screen you are
waiting 1-2 seconds.

I see that suspend and resume layout have been removed from the CF,
but what other options do I have to prevent the UI from killing the
performance.

Code snipits:

public void NavigationPanel_Clear()
{
int x1 = Environment.TickCount;

this.navigationPanel.Controls.Clear();

int x2 = Environment.TickCount;
x2-=x1;
string msg = String.Format("Ending UIForm.NavigationPanel_Clear
took: {0} ms",x2.ToString() );
LogClass.AddLogEntry(SEVERITY.PERFORMANCE, msg);

}

public void NavigationPanel_View(Control ctrl)
{
int x1 = Environment.TickCount;

ctrl.Show();
this.navigationPanel.Controls.Add(ctrl);

int x2 = Environment.TickCount;
x2-=x1;
string msg = String.Format("Ending UIForm.NavigationPanel_View
took: {0} ms",x2.ToString() );
LogClass.AddLogEntry(SEVERITY.PERFORMANCE, msg);
}

I have already tried usind hide and show on the controls and this
worked great until we got more than 200 controls. At that point it
was taking 30 seconds to go from one screen to the next.

thanks,
Shane
 
C

Chris Tacke, eMVP

See if parenting them manually works better.

So instead of :
myForm.Controls.Add(myControl)
use:
myControl.Parent = myForm
 
S

Shane

Chris,

Thank you for your suggestion.

This had no change in the speed. I think we are going to have to go
to interopt code to prevent the UI from updating. My theory is a
thread in the background is doing some work everytime something in the
Controls array is changed. Can somebody shed some light on what is
going on so I know what to target? The remote performance tool from
EVC 4.0 is useless via USB and the PDA (it slows everything to a crawl
without anything running). I dont see any way in remote Spy++ to see
events. Any suggestions on how to test my theory?

Some ideas I have tried that did not work:
1 Changed the priority of my thread to highest right before I do the
clear and add. Some studdering happened but no hugh change in speed.
2 Disabled the panel before the changes. This made a nifty looking
fade effect happen, but no change in the speed.
3 Used show and hide instead of add and clear, this worked well until
we got about 200+ controls and then things started taking 30 seconds
to hide 10 things.
4 Did the add before the remove. No change in speed.
5 Changed the parent of the controls instead of add/remove. No change
in speed.

thanks,
Shane
 
G

Guest

I have the same problem!
it's a bug in the SP2.

The solution is to uninstall SP2 or to call the Dispose method of all
Controls object in the panel.

sample:
int nb=this.navigationPanel.Controls.Count;
for (int i=0;i<nb;i++)
{
Control c=this.navigationPanel.Controls[0];
this.navigationPanel.Controls.RemoveAt(0);
c.Dispose();
}


You can check the bug with this sources:

using System;
using System.Drawing;
using System.Collections;
using System.Windows.Forms;
using System.Data;
using System.Runtime.InteropServices;

namespace BugPanel
{
/// <summary>
/// Description résumée de Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.ListBox listBox1;
private System.Windows.Forms.Button button2;
private System.Windows.Forms.Button button3;
private System.Windows.Forms.Panel navigationPanel;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.RadioButton radioButton1;
private System.Windows.Forms.RadioButton radioButton2;
private int cycle=0;

public Form1()
{
//
// Requis pour la prise en charge du Concepteur Windows Forms
//
InitializeComponent();

//
// TODO : ajoutez le code du constructeur après l'appel à
InitializeComponent
//
}
/// <summary>
/// Nettoyage des ressources utilisées.
/// </summary>
protected override void Dispose( bool disposing )
{
base.Dispose( disposing );
}
#region Code généré par le Concepteur Windows Form
/// <summary>
/// Méthode requise pour la prise en charge du concepteur - ne modifiez pas
/// le contenu de cette méthode avec l'éditeur de code.
/// </summary>
private void InitializeComponent()
{
this.navigationPanel = new System.Windows.Forms.Panel();
this.button1 = new System.Windows.Forms.Button();
this.listBox1 = new System.Windows.Forms.ListBox();
this.button2 = new System.Windows.Forms.Button();
this.button3 = new System.Windows.Forms.Button();
this.radioButton1 = new System.Windows.Forms.RadioButton();
this.radioButton2 = new System.Windows.Forms.RadioButton();
//
// navigationPanel
//
this.navigationPanel.BackColor = System.Drawing.Color.Brown;
this.navigationPanel.Location = new System.Drawing.Point(16, 8);
this.navigationPanel.Size = new System.Drawing.Size(192, 24);
//
// button1
//
this.button1.Location = new System.Drawing.Point(16, 64);
this.button1.Size = new System.Drawing.Size(40, 24);
this.button1.Text = "Go!";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// listBox1
//
this.listBox1.Location = new System.Drawing.Point(8, 96);
this.listBox1.Size = new System.Drawing.Size(192, 171);
//
// button2
//
this.button2.Location = new System.Drawing.Point(64, 64);
this.button2.Size = new System.Drawing.Size(40, 24);
this.button2.Text = "Stop";
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// button3
//
this.button3.Location = new System.Drawing.Point(144, 64);
this.button3.Size = new System.Drawing.Size(40, 24);
this.button3.Text = "Clear";
this.button3.Click += new System.EventHandler(this.button3_Click);
//
// radioButton1
//
this.radioButton1.Checked = true;
this.radioButton1.Location = new System.Drawing.Point(16, 40);
this.radioButton1.Size = new System.Drawing.Size(80, 16);
this.radioButton1.Text = "MS Clear";
//
// radioButton2
//
this.radioButton2.Location = new System.Drawing.Point(112, 40);
this.radioButton2.Size = new System.Drawing.Size(80, 16);
this.radioButton2.Text = "ViL Clear";
//
// Form1
//
this.ClientSize = new System.Drawing.Size(194, 295);
this.Controls.Add(this.radioButton1);
this.Controls.Add(this.listBox1);
this.Controls.Add(this.button1);
this.Controls.Add(this.navigationPanel);
this.Controls.Add(this.button2);
this.Controls.Add(this.button3);
this.Controls.Add(this.radioButton2);
this.MinimizeBox = false;
this.Text = "BugPanel";
this.Load += new System.EventHandler(this.Form1_Load);

}
#endregion

/// <summary>
/// Point d'entrée principal de l'application.
/// </summary>

static void Main()
{
Application.Run(new Form1());
}

private void Form1_Load(object sender, System.EventArgs e)
{

}


public void NavigationPanel_Clear()
{
int x1 = Environment.TickCount;
int nb=this.navigationPanel.Controls.Count;
if (radioButton2.Checked)
{
//vil clear
for (int i=0;i<nb;i++)
{
Control c=this.navigationPanel.Controls[0];
this.navigationPanel.Controls.RemoveAt(0);
c.Dispose();
}
}
else
{
//ms clear :( :
this.navigationPanel.Controls.Clear();
}
int x2 = Environment.TickCount;
x2-=x1;
string msg = String.Format("{0} Panel_Clear: {1}
ms",cycle.ToString(),x2.ToString() );
Trace(msg);
}

public void NavigationPanel_View(Control ctrl)
{
//int x1 = Environment.TickCount;


//ctrl.Parent=this.navigationPanel();
this.navigationPanel.Controls.Add(ctrl);
//ctrl.Show();
//int x2 = Environment.TickCount;
//x2-=x1;
//string msg = String.Format("Panel_View: {0} ms",x2.ToString() );
//Trace(msg);
}

private void button3_Click(object sender, System.EventArgs e)
{
listBox1.Items.Clear();
}

private void Trace(string msg)
{
listBox1.Items.Insert(0,msg);
}
private void button1_Click(object sender, System.EventArgs e)
{
Control c;

button1.Enabled=false;
button2.Enabled=true;
button3.Enabled=false;
for (int j=0;j<100;j++)
{
Application.DoEvents();
cycle++;
//Application.DoEvents();
//SuspendLayout();
//Add textbox
for (int i=0;i<3;i++)
{
c = new TextBox();
NavigationPanel_View(c);

}

//Add Label
for (int i=0;i<5;i++)
{
c = new Label();
NavigationPanel_View(c);
}
//ResumeLayout();

NavigationPanel_Clear();
}

button1.Enabled=true;
button2.Enabled=false;
button3.Enabled=true;
}

private void button2_Click(object sender, System.EventArgs e)
{
}
}
}


I's there somebody in Microsoft to test Service pack?????
Vinch
 

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