How do I speed optimize Windows Forms applications?
I am not talking about apparent .NET optimisation techniques - like NGEN-ing, caching objects, etc. I already tried that and what I am up to is to reduce the form initilization time from a 1500 msec down to 500 msec.
Profiling has identified the slowest code and almost all of it is in the InitializeComponent, and within this method the slowest lines is
creation of the (just new-ing) WebBrowser component
loading icon from a resource (hideous 500 msec)
creation of the ContextStripMenu
several this.Controls.Add() calls contribute a lot too.
At the moment, I can only see how to fix point (2) - move icon data from being stored as embedded resource to a private field (for example, Base64-encoded string).
What what should I do with points 1, 3 and 4?
Load the icon in a separate InitializeComponentAsync thread.
The only thing I can think of that you could do is rewrite the controls that you want to use and optimize them to initialize faster (as well as the Form class to optimize adding the adding of the controls to the form).
I can't see how that is feasible though, and I think you are going to be stuck with this, depending on your reliance on these controls.
One technique I have used in the past was to multi-thread the data load, so that it runs simultaneously to the form creation. In this instance data was being loaded out of AD, it cut about 1/3 of the load time.
I have changed the strategy of form loading, this will make a great change on form load timing, now it's taking an average of 37 ms instead of 466 ms.
Method: On First time Click on Top-tab/Icon, application load all form under that tab/icon and on click on Form Icon it will only switch visibility. And again visit on Top-tab will not load the form under that tab.
Just take another class like ClsAppearance.cs as I taken.
Initialize all controls like
static Infragistics.Win.Appearance txtBoxMidAppr = null;
I take my own name like txtBoxMidAppr instead if the appiarance1. due to it can be use for all textbox, by only once initialization.
Make a function where we can initialize the appearance and call it on the MDI/Main form loading only once.
public static void LoadAll()
{
txtBoxMidAppr = new Infragistics.Win.Appearance();
}
Make another function here and take the appearance code from designing window
public static Infragistics.Win.Appearance App_txtBoxMidAppr //text_box_small
{
get
{
txtBoxMidAppr.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(93)))), ((int)(((byte)(93)))));
txtBoxMidAppr.ImageBackground = global::CS_POS.Properties.Resources.text_box_small;
txtBoxMidAppr.ImageBackgroundStyle = Infragistics.Win.ImageBackgroundStyle.Stretched;
txtBoxMidAppr.ImageHAlign = Infragistics.Win.HAlign.Right;
return txtBoxMidAppr;
}
}
In the designing code of the form, comment all appearance setting of the text box and put the function name for getting appearance from the ClsAppearance.cs class
//appearance4.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(93)))), ((int)(((byte)(93)))));
//appearance4.ImageBackground = global::CS_POS.Properties.Resources.text_box_small;
//appearance4.ImageBackgroundStyle = Infragistics.Win.ImageBackgroundStyle.Stretched;
//appearance4.ImageHAlign = Infragistics.Win.HAlign.Right;
this.uteNABoth.Appearance = CS_POS.App_Appearance.ClsAppearance.App_txtBoxMidAppr;
take all controls appearance and make a function in the class and call it from there.
So the appearance initialization will goes only once and can use many time.
Can you do lazy loading for your Webbrowser control? If it's in a tab which is not the main view then you might load webbrowser when that tab is activated.
Or you might load the form and then load the webbrowser (this might help you to show something first and then show everything, just like you'd do in a website).
Related
I am reusing the same code for clearing the screen many times in my program, and I thought about turning it into a class, but I still don't get how classes work and how to properly make one.
My code to clear buttons and other controls is as follows:
List<RichTextBox> _richTextBoxes = this.Controls.OfType<RichTextBox>().ToList();
List<Button> _buttons = this.Controls.OfType<Button>().ToList();
List<Label> _labels = this.Controls.OfType<Label>().ToList();
List<TextBox> _textBoxes = this.Controls.OfType<TextBox>().ToList();
foreach (var rich in _richTextBoxes)
{
this.Controls.Remove(rich);
}
foreach (var button in _buttons)
{
this.Controls.Remove(button);
}
foreach (var label in _labels)
{
this.Controls.Remove(label);
}
foreach (var textBox in _textBoxes)
{
this.Controls.Remove(textBox);
}
As others already mentioned, it's a rare practice to remove/create all controls of a container (Form, Panel, etc) at runtime, and a possible waste of PC resources.
Of course you can use:
Form.Controls.Clear();
Or
Panel.Controls.Clear();
But, what's wrong with placing all your controls in a Panel, for example, and simply hiding said panel? seen you get the same result in a more efficient way
If you opt for this, it's as simple as this line:
Panel.Visible = false; // or true
Hiding 100s or 1000s of controls is inefficient and wasteful
Contrary to the other answer's idea that
Panel.Visible;
...is somehow more efficient, it is not. Hiding a control does not release any resources the control might have requested the obvious being a window handle. Handles, fonts etc are all part of the GDI pool, a rather limited resource. Depending on what version of Windows you are running you might be limited to anything between 256 and 16,384 GDI handles per process.
So think before hiding 100s of controls. Much better to just destroy the unwanted and create the ones you need.
Back to the question
I am reusing the same code for clearing the screen many times in my program
The bigger question is why you want to do that?
Though a legitimate programming scenario, given that "but I still don't get how classes work" , it is unlikely you are at the dynamic-UI-apps stage based on say dynamic selection of a database table.
Consider creating multiple forms via the Designer and don't modify them at runtime. That's alot easier if dynamic UIs isn't really a requirement.
An easier way to change things at runtime
Otherwise if you are super keen to continue with changing things at runtime, consider placing all the controls in a child Panel belonging to the form.
Then you can just call Clear():
myPanel.Controls.Clear(); // Job done
So here's my Question, I'm new to C#(teaching my self at that) Here's the thing, I'm working on a basic sim game, nothing to complex but I've got the design and basic functions done.
However In order to implement it, I'm currently using multiple Forms(Visual Studio 2013)
I have my "main" form which has the "action" buttons to it
So when i want to go to a user Profile page I have
Btn_profileview Click(object sender, EventArgs e){
Form profile = new Form();
profile.Show();
}
The User would then implement the changes(for instance change name) which is written to a text file, for use in other areas of the program.
However It opens a new windows, I've tried modal and nonmodal windows and while the benefit of Modal so they have to actual close the window solves the issue, i'd rather have it just overwrite the preexisting Form, and then on close go back to the "main" screen without actually using multiple windows.
Now I was told UserControl and/or Panel would solve the issue, but it would cause a complete redesign moving from the multiple forms to the multiple panel screens and figuring out how to get those to work(Visible and Invisible), i'm assuming it wouldn't be extremely difficult something along the lines of Panel"name".show(); and panel"name".close();
But would it be possible to actually add a line of code to the pre-existing code(so as not to cause a complete reesign) or are Panels and UserControl the only real way to implement within 1 continuous windows?
paqogomez is right: There are many ways to do it.
Here is one that combines a lot of the pros:
You create an invisible Tab on your window with as many pages as you need. Place a Panel on each tab and create all your controls on of them. This does not mean that you have to do it all over - you can move and drop the controls you already have without much hassle. Of course you need to turn off docking and maybe anchors, but other than that this is a simple process.
If you have controls on the 2nd form with the same name, these names should be changed to something unique though. I hope all Controls have proper names already, but especially Labels get neglected, at least here.. (With a little luck you can even use cut and paste to get Controls from another form to panel2!)
The big pro of this trick is that you can do all work in the designer of the same form. The Tab control serves only as a container where you keep your panels without adding to the UI and without giving the user control of what is shown.
Next you create one Panel variable in your main form:
Panel currentPanel;
On Load you assign the first 'real' Panel to it like this:
currentPanel = panel1;
this.Controls.Add(currentPanel);
Later, each time you want to switch, you re-assign the panels you need like this:
this.Controls.Remove(currentPanel);
currentPanel = panel2; // or whichever panel you want to show..
this.Controls.Add(currentPanel );
If your real panels are docked to fill the tabpage, as they should, the currentPanel will fill the form. You still have access to each panel and to each control by their names at any time but you see no overhead of tabs and your form never changes, except for the full content.
Warning! This is noob question probably! Sorry in advance.
I'm learning C# (using MS Studio 2013) and I'm having hard time creating some kind of decent navigation in simple desktop program.
Basically what I want is this: MenuStrip with options like "calculate something", "Calculate somethingelse"... and other (that I can easily add later - like dynamic menu on a webpage). If you click first option inside the Form connected with the StripMenu you will get some controls that allows you to do something(like inputs on a webpage). If you click the second all these options will disappear and you will get a fresh set of controls where you can do somethingelse (simply another webpage to play with).
What is the best way to do it (I find it amazing hard to find out :) ). Only way I figured out (more from experience in js then tutorials) is to use show/hide like in javascript/html.
ExamplePanel.Visible = false;
ExampleOtherPanel.Visible = true;
But this doesn't seem right - I think it would be impossible to manage in bigger program (not only in code, but visual designer too - you can only fit that much Panels inside Form).
Any advice? Or at least a link to material where I can find out?
EDIT:
Finaly I gave up and used multiple Forms as sugested in answer.
private void MenuStripExample_Click_1(object sender, EventArgs e)
{
SomeForm SomeForm = new SomeForm();
this.Hide(); //Hide the main form before showing the secondary
SomeForm.ShowDialog(); //Show secondary form, code execution stop until SomeForm is closed
//this.Show(); //You may uncomment this if you want to have the previous Form to get back after you close new one
}
You normaly don't hide and show panels with different layouts. This is not a good design.
If you have complete different navigations/control sets, then create a new Form which is responsible for the control set.
If you don't want to use new Forms take a look at the TabControl.
You may also want to take a look at MDI-Container. You can use a Form as a MDI-Container and display various other Forms as child-elements inside of this container.
I got a problem with form.Show() in C# .NET Framework 2.0.
//segment code (FormA's caller)
FormA frmA = new FormA();
writeLog("Begin: " + Environment.TickCount);
frmA.SuspendLayout();
frmA.Show();
frmA.ResumeLayout();
writeLog("End: " + Environment.TickCount);
....
//segment code (FormA)
private void FormA_Load(object sender, EventArgs e){
writeLog("Begin - Load: " + Environment.TickCount);
}
From above segment code, I build in release mode and execute it.
I found diffrent time between "Begin:" and "Begin - Load" about 2 - 3 second on my notebook (Windows XP x86), yet different time on Server (Windows 2003 SP2) is more than 5 second.
I don't know why.
In addition, FormA have many TableLayout and UserControl (total controls approximate 800 )
If you've profiled and optimized your form, you might have to use a wait cursor, a splash screen or a progress bar.
If you have NOT profiled, I strongly recommend you do so. There may be a few methods that eat up a lot of time.
If you have a lot of controls (800 you say?) in your form, you might consider modifying the form's initialization to use a backgroundworker - essentially you load your controls in a separate thread. This may or may not be possible, given your specific requirements.
Edit:
I assumed in my answer that your 800 controls were necessary - it's very likely that you can reorganize your code to load controls only when needed. If you're not immediately able to reorganize your code, profiling to find the worst culprits is a good second choice.
Profile your initialize component method. Do you have non native controls? Third party ones? Some of them are notoriously slow to render. Are you setting the datasource for any of the controls? Populating a control with items at design time? Try to move them after your page load.
And yes, 800 controls is a page. That's just a badly designed page. Fix that first.
I think profiling the form might not be what you need, but rather profiling the user controls.
Or even better. If you have tabs in you form, maybe you can move the loading of controls to when a tab is fiven the focus for the first time. Only load tose cotrols that will be visible to the user on startup, then load the rest on request.
Short version: I want to trigger the Form_Load() event without making the form visible. This doesn't work because Show() ignores the current value of the Visible property:
tasksForm.Visible = false;
tasksForm.Show();
Long version: I have a WinForms application with two forms: main and tasks. The main form is always displayed. The user can either click a button to open the tasks form, or click some buttons that just run a task directly without opening the tasks form.
When a user asks to run a task directly, I'd like to just call some public methods on the tasks form without showing it. Unfortunately, the task logic depends on stuff that happens in the Form_Load() event. The only way I can find to trigger Form_Load() is to call Show(). The best I've been able to do is to show the form in the minimized state:
tasksForm.WindowState = FormWindowState.Minimized;
tasksForm.Show();
I suppose the cleanest solution would be to pull the tasks logic out of the tasks form and into a controller class. Then I can use that class from the main form and from the tasks form, and only load the tasks form when I need it visible for the user. However, if it's an easy thing to load the form without displaying it, that would be a smaller change.
Perhaps it should be noted here that you can cause the form's window to be created without showing the form. I think there could be legitimate situations for wanting to do this.
Anyway, good design or not, you can do that like this:
MyForm f = new MyForm();
IntPtr dummy = f.Handle; // forces the form Control to be created
I don't think this will cause Form_Load() to be called, but you will be able to call f.Invoke() at this point (which is what I was trying to do when I stumbled upon this SO question).
It sounds to me like you need to sit down and re-think your approach here. I cannot imagine a single reason your public methods need to be in a form if you are not going to show it. Just make a new class.
I totally agree with Rich B, you need to look at where you are placing your application logic rather than trying to cludge the WinForms mechanisms. All of those operations and data that your Tasks form is exposing should really be in a separate class say some kind of Application Controller or something held by your main form and then used by your tasks form to read and display data when needed but doesn't need a form to be instantiated to exist.
It probably seems a pain to rework it, but you'll be improving the structure of the app and making it more maintainable etc.
From MSDN:
Form.Load
Occurs before a form is displayed for the first time.
Meaning the only thing that would cause the form to load, is when it is displayed.
Form.Show(); and Form.Visible = true; are the exact same thing. Basically, behind the scenes, Show checks for various conditions, then sets Visible to true. So obviously, setting visible to false (which it already is) before showing the form is meaningless.
But let's forget the technicalities. I completely agree with Rich B and Shaun Austin - the logic shouldn't be in that form anyway.
Sometimes this would be useful without it being bad design. Sometimes it could be the start of a migration from native to managed.
If you were migrating a c++ app to .NET for example, you may simply make yourwhole app a child window of the .NET form or panel, and gradually migrate over to the .NET by getting rid of your c++ app menu, status bar, toolbar and mapping teh .NEt ones to your app using platform invoke etc...
Your C++ app may take a while to load, but the .NET form doesn't..in which you may like to hide the .NEt form until your c++ app has initialised itself.
I'd set opacity=0 and visible=false to false after calling show, then when your c++ app loads, then reverse.
If you make the method public, then you could access it directly.... however, there could be some unexpected side effects when you call it. But making it public and calling it directly will not draw the screen or open the form.
Move mandatory initialization code for the form class out of the Load event handler into the constructor. For a Form class, instantiation of an instance (via the constructor), form loading and form visibility are three different things, and don't need to happen at the same time (although they do obviously need to happen in that order).
None of the answers solved the original question, so, add the below, call .Show() to load the form without showing it, then call .ShowForm() to allow it to be visible if you want to after:
private volatile bool _formVisible;
protected override void SetVisibleCore(bool value)
{
base.SetVisibleCore(_formVisible);
}
public void ShowForm()
{
_formVisible = true;
if (InvokeRequired)
{
Invoke((Action) Show);
}
else
{
Show();
}
}