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.
Related
My application has ATL-based GUI (CWnd, CDialog,...) and it consists of multiple pages (CDialog). One of these pages is otherwise empty but it has a placeholder frame (CWnd) that resizes with the dialog. Everything is built as x64.
When the page loads, it asks for a control handle from managed (C#) side of the application using COM-interop, and adds the control to the dialog as CWnd that is created from that handle:
Managed implementation simplified:
// Class "ManagedControlProvider"
private Control myUserControl;
public long CreateControl()
{
myUserControl = /*Create some new inheritant of UserControl */
myUserControl.Dock = DockStyle.Fill;
return myUserControl.Handle.ToInt64();
}
Native side simplified:
// Call the managed class. Lifetime of m_pManagedControlProvider
// is ensured elsewhere.
LONGLONG lHandle = m_pManagedControlProvider->CreateControl();
// m_pUserCtrlAsCWnd is CWnd*
m_pUserCtrlAsCWnd = CWnd::FromHandle((HWND)lHandle);
m_pUserCtrlAsCWnd->SetParent(this);
// m_ControlFrame is just a native helper-CWnd the dialog that
// resizes with it a so gives us the size we want to set for the
// managed control. This code is also call in every resize -event.
RECT winRect;
m_ControlFrame.GetWindowRect(&winRect);
ScreenToClient(&winRect);
m_pUserCtrlAsCWnd->SetWindowPos(NULL,
winRect.left, winRect.top, winRect.right - winRect.left,
winRect.bottom - winRect.top, 0);
I have done this multiple times and it usually works exactly as is should. But sometimes, like now, I'm experiencing application hangs without any clear reason. With my current control this seems to happen roughly 5s after the focus is set to some other desktop application.
I have verified that the issue is not in the managed control's lifetime or GC. Also it's reproducible in debug build so optimizations are not to blame. When the hang occurs, I can attach debugger and see that some ATL loop keeps on going but that's the only piece of code I'm able to see in stack (imo this indicates that the message loop is somehow caught in infinite loop without interacting with my code).
Now for the dirties fix ever: I added a separate thread to my managed control that invokes this.Focus() every second on the UI thread. Obviously this is a ridiculous hack but it works as long as I pause the focusing everytime user opens combos etc (otherwise they get closed every second).
What am I doing wrong or what could cause this somewhat unpredictable behavior?
I don't know why or what it has to do with anything, but the application hang somehow originated from WM_ACTIVATE. So the solution was to override WINPROC at the main CDialog and block forwarding of that message. Everything has been working without any issues since then.
I'll not mark this as answer because I don't know why this solution works.
We are developing Automation Software for Restaurants(using VS.NET C#). And we are using POS products which mostf of them has celeron or atom processor with 512 mb or 1gb ram on it. So at the begining know that we can't get more powerfull PC(i saw suggestion like "Get a better PC to your customer" :) ).
We have a memory problem. To represent the cart of a real customer, we use panel, we add custom control to represent product in cart. These means lots of controls are adding to panel, then removing(Panel.controls.Clear function.) This method causes a memory leak and program goes slow performance. After searching and googling, i found that Panel.Control.Clear() funtction clears all the control in the panel but not from the memory. So i disabled the panel to check, and wholaaa everything workss fine. No memory leaks anymore. So i decided to remove that cart panel to save memor. But later i found very usefull suggestions here, like EmptyWorkingSet.
[DllImport("psapi.dll")]
static extern int EmptyWorkingSet(IntPtr hwProc);
static void MinimizeFootprint()
{
EmptyWorkingSet(Process.GetCurrentProcess().Handle);
}
Then i added the code , enabled the cart panel, and it nothing changed. Performance is still good.No memory leak, no performance decreased. But some says in here and here EmptyWorkingSet may causes Page Faults and it is dangerous. I'am testing program and nothing happened. It works like a charm. So these are my options
Remove the cart panel that causes memory problems.
After clearing custom controls from cartPanel , remove the custom controls from the memory( i don't know how but i can figure it out)
USE EmptyWorkingSet but it may cause page faults(truely i don't know what is that Page Fault mean)
SO WHAT DO YOU SAY
I think the problem is that you're clearing the collection of controls, when you should be disposing them. Also, be sure you're unhooking any event handlers to the the controls before you clear them as well, as event handlers setup references between objects, so the listener of the event will cause an otherwise eligible for collection object to stick around. I'd go that route before trying to force the working set to be cleared.
I'm trying to make a listbox that display pictures from internet. The items are provided by binding itemsource to a model that contain the URL of the image and some other properties (title, desc, etc...).
Unfortunately, the list is very slow to load because WPF is trying to download all pictures from the web before showing the list and it makes the application freeze for 15 to 25 sec.
I've read that I should load the picture in an other thread but I don't know where I should do it and how ? Is it better to load all pictures directly in the model (by creating a thread pool only for that - but the problem is that it's not really part of the model/modelview) or is that better to create a background thread that will update directly the list when it has data ?
Thanks !
The easy way is to just just set the Binding.IsAsync property like this:
<Image ImageSource="{Binding propertyThatComputesImageSource, IsAsync=true}" />
Each access to propertyThatComputesImageSource will be done from a ThreadPool thread. If the thread creates the image with ImageCacheOptions.OnLoad, it will block until the image is loaded. So the UI will start up immediately and images will be loaded in the background and appear when they are available.
Binding.IsAsync is a good solution for ten or twenty images, but is probably not a good solution if you have hundreds of images and the load delay is long, since you could end up with hundreds of threads. In that case, load the images outside of databinding entirely by using ThreadPool directly:
ThreadPool.QueueUserWorkItem((state) =>
{
foreach(var model in _models.ToArray())
model.ImageSource = LoadOneImage(model.ImageUrl);
});
This may need to be extended with a Dispatcher.Invoke or two if the model's properties are DependencyProperty, since they can't be accessed from a separate thread.
This technique can be extended to spawn a fixed number of workers to load images and break the work up between them so multiple image downloads are happening, but the number of simultaneous downloads is limited so you don't end up with hundreds of threads.
A very simple approach would be to use a System.ComponentModel.BackgroundWorker (more info) in the view model. Here's a trivial example:
using (BackgroundWorker bg = new BackgroundWorker())
{
bg.DoWork += (sender, args) => FetchImages(viewModelObjectsNeedingImages);
bg.RunWorkerAsync();
}
The BackgroundWorker also makes it very convenient to cancel the background task.
You might also want to look at UI virtualization.
You can use this asynchronous observable collection to be able to bind your data source to your ListBox and still be able to load your data in another thread.
For an example on how to write such a thread, take a look at the BackgroundWorker documentation.
Also, you might want to consider lazy loading of your images, that is, only load the ones that are visible and a couple more at any time. This way, you gain two benefits: don't have to block the UI while fetching the images in your thread, and you can reuse your collection to only hold a few images at a time, preventing filling up the memory with lots of images at once if you plan on displaying, say, a couple of thousand. Take a look here for details on how such virtualization could be implemented.
Thanks to all of you !
All solutions should work :) In my case using IsAsync on the image of the ListBoxItem is good enough (at most there are 50 items). Actually, it's not retrieving the image from a network which was taking too much time !
Unfortunately my problem was somewhere else... It's related to a bug with proxy detection in .NET 3.5 which cause the application to load very slowly :
If there isn't any your_application_name.exe.config file in the application folder with the following code - .NET can take a lot of time to detect the proxy which freeze the application the first time that it accesses to a network :
<configuration>
<system.net>
<defaultProxy enabled="false"/>
</system.net>
</configuration>
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).
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();
}
}