I am optimizing the startup of a WinForms app. One issue I identified is the loading of the splash screen form. It takes about half a second to a second.
I know that multi-threading is a no-no on UI pieces, however, seeing how the splash screen is a fairly autonomous piece of the application, is it possible to somehow mitigate its performance hit by throwing it one some other thread (perhaps in the way Chrome does it), so that the important pieces of the application can actually get going.
The .NET framework already has very good support for splash screens in Windows Forms apps. Check this thread for a code sample. It is indeed optimized for warm startup time, it makes sure the splash thread and screen is up and running before initializing the main app.
There's nothing to be gained from spawning a thread if your goal is to get the splash screen up as quickly as possible.
There are several ways to do splash screens, and a more sophisticated one is mentioned here, but this is an easy method I have used with complete success:
Just ensure you load and show the splash form first, and then continue to load your app while the user is looking at the pretty splash screen. When the mainform is done loading, it can close the splash right before it shows itself (a simple way to do this is pass the splash form to the mainform in its constructor):
static void Main()
{
Application.SetCompatibleTextRenderingDefault(false);
SplashForm splash = new SplashForm();
splash.Show();
splash.Refresh(); // make sure the splash draws itself properly
Application.EnableVisualStyles();
Application.Run(new MainForm(splash));
}
public partial class MainForm : Form
{
SplashForm _splash;
public MainForm(SplashForm splash)
{
_splash = splash;
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
// or do all expensive loading here (or in the constructor if you prefer)
_splash.Close();
}
}
Alternative: If you prefer not to pass the splash to the MainForm (maybe it seems inelegant), then subscribe to the MainForm's Load event, and close the splash screen there:
static class Program
{
static SplashForm _splash;
[STAThread]
static void Main()
{
Application.SetCompatibleTextRenderingDefault(false);
_splash = new SplashForm();
_splash.Show();
_splash.Refresh();
Application.EnableVisualStyles();
MainForm mainForm = new MainForm();
mainForm.Load += new EventHandler(mainForm_Load);
Application.Run(mainForm);
}
static void mainForm_Load(object sender, EventArgs e)
{
_splash.Dispose();
}
}
As mentioned in this thread, the potential downside to this solution is that the user won't be able to interact with the splash screen. However, that usually isn't required.
Multithreading in WinForms is okay as long as all the UI stays on one thread.
This is just how splash screens are usually done. The important work is done on a background thread, while the splash screen window is shown on the UI thread to let the user know that the rest of the program will appear soon.
After the important stuff has happened, raise an event to let the UI thread know that it is time to hide the splash screen (just remember to marshal the event handler, using Invoke(), back onto the UI thread in order to close the splash screen).
Yes.
You need to make a new STA thread that shows the splash screen using Application.Run, then call Close using Invoke after the main form is ready (on the main thread).
EDIT: For example:
static SplashForm splash;
Thread splashThread = new Thread(delegate() {
splash = new SplashForm();
Application.Run(splash); //Blocking call on separate thread
});
splashThread.SetApartmentState(ApartmentState.STA)
splashThread.Start();
LoadApp();
//In MainForm_Shown:
splash.BeginInvoke(new Action(splash.Close));
For optimal performance, you should make your Main method show the splash screen, then call a separate method that loads the application. This way, all of the assemblies will be loaded after the splash screen is shown. (When you call a method, the JITter will load all of the types that it uses before the method starts executing)
The answer is really about perception. There are various methods, NGEN an assembly, putting things in the GAC, but what you should understand is what is really going on.
C# require time to load the virtual machine, load referenced assemblies, and load assemblies based upon what is on that splash screen. And then it still takes awhile from a "cold" start to launch the first screen.
This is because of the JIT compiling that is going on when you first access a screen.
A strategy that I use is a traditional lightweight splash page that loads quickly so its visible, but in the background I spawn a thread and load an invisible form. This form has all the controls that I intend to use and so the JIT compiler is doing its thing and its loading the assemblies. This provides the illusion of responsiveness with slight of hand. The time it takes from launch + visible splash page + pause + time to click 1st option is greater then the time it takes for the thread to execute and then cleanup and unload the form.
Otherwise, applications appear to be clunky and slow for users when it first starts. Warm startup of screens is much faster because the assemblies and JIT has finished.
We do it by providing a tiny small native C++ application that serves as the splash screen.
It then follows this process:
User double clicks the application icon.
The C++ app starts, showing a splash bitmap as WS_TOPMOST.
The C++ app launches the main C# app.
The C# app starts, finally notifying the C++ app (through a simple file) to quit.
The C++ app quits.
The C++ application also has a timeout (in case the C# app crashes) and quits automatically if it does not get notified to quit within 30 seconds.
This approach has its drawbacks in the fact that you cannot pin the application to the task bar. If you pin the C++ app (which is the main app for the end user), you get another task on the task bar, because the C# app is different. I think, I could solve this by providing settings in the application manifest of both the C++ and C# application to instruct them to be the "same" application in terms of the task bar.
Related
Background:
I'm trying to add an animation to a splash screen window in my WPF project. (Not using the actual SplashScreen control. I use a window.)
My reason for implementing the splash screen is beacuse there's a slight delay when the application is opened, due to the loading of data. Obviously, the splash screen's purpose is to aid the user experience, so the user knows the application has been executed.
Here's the idea behind my current approach:
Instantiate the splashscreen window at the beginning of the
constructor.
InitializeComponent() is called.
Close the splashscreen window.
Unfortunately, the animation in the splash screen doesn't start until after the InitializeComponent() method of the the main parent window is called; this occurs basically when I'd WANT TO close the splashscreen window anyway. Hence the animation is useless and doesn't start until it's too late.
My question:
Why does it not animate until after InitializeComponent() is called?
My current theory for why this happens is that it's because the splash
screen is being opened on the main UI thread. Am I correct?
Are there any workarounds that don't involve hijacking control of
the program and spawning the splashscreen in a new thread? (I don't want a solution that hackish)
And yes, I did browse this site for quite awhile and was unable to find a viable solution.
Processing time on the UI thread blocks the animation. No real way around it.
The best approach is to NOT spend so much time loading and blocking on the UI thread. I suggest that you could delay the loading of the data bound to your UI elements until after the initial load. That way, the InitializeComponents() should not take so long.
Basically, all your bindings should return no data to the controls until AFTER you initialize. This data initialization would preferably happen on a separate thread, and then notification would occur after the data has been loaded.
This would allow your splash screen to animate and you will have much more joy.
There are a few approaches that I've taken to handle this in the past, though #HighCore is right in the comments as well about your current problem
Use the SplashScreen class in the VisualBasic assembly
Use the WPF Splash Screen class
Regardless, these solutions boil down to threading, since the UI pipeline needs to render and you can't inherently do these things on the UI thread without blocking, particularly if you want animation.
Using the CoreScanner Driver provided by Motorola, I'm trying to write a small winforms application that uses a barcode scanner. I'm able to interact with the scanner just fine, and properly register a call back for the OnBarcodeEvent(). In this callback, I have a Dialog that opens and displays a screen that the user needs to fill in. Shortly after the dialog is opened (using Show()), the program hangs. If I use ShowDialog(), the dialog works, but the dialog is blocking the OnBarcodeEvent event.
My guess to what is happening, is that since the dialog is getting created on the event thread, there is a race condition occurring when using Show(). Since Show() is non-blocking, the thread continues on after displaying the dialog and then dies out. Meanwhile my dialog just lost it's parent and locks up? Like i said... my best guess.
How can I remedy the situation? That is, How do I write my dialog so that it can be created within a thread not hang?
In the event, you should launch a different thread that will create your dialog form and show the form on it. You need to block this thread till form is visible - this is possible either by ShowDialog or alternately use one of Application.Run overload.
Yet another option would be to show the form on the UI thread (i.e. main application thread) - to do that, you need to call Invoke method on your main form from the event code. The invoke call should take the delegate that will show your dialog form non modally.
I have some experience with Motorola/Symbol Handheld-Devices (MC9090) and I guess the SDK will be similar.
It's hard to say without seeing the code, but my guesses:
your common not-UI thread problem - so make sure you open your dialog using UI thread
the native Motorola-driver is crashing - no kidding, this happened a lot to me - in my case (compact-framework on a WinCE device) this would not freeze the program but the scanner will not work/receive any messages before restarting the device
In order to fix this you should seperate the showing/handling of user-dialog away from the event and make sure you call this on the UI-thread (Control.InvokeRequired / Control.Invoke).
when my program in any process (load csv file for example)
i see 'program Not Responding' and i see black screen - in Windows-7
in Windows-XP i dont see it
(after this the program Continues normal)
Why is this happening ?
When a long process is running, if it's running on the UI thread, that causes the application to not respond to other UI events, most notably drawing the screen. In both Windows XP and Windows 7, this will cause application to be reported as "not responding", but XP and Windows 7 handle window painting differently.
In XP, the application actually updates the screen, but in windows 7, the OS saves what the current screen looks like, then displays that on the screen using a different mechanism (for example, with Aero enabled, it actually displays the contents of the windows using textures in pseudo-3D).
In 7, this can cause applications that are not responding to display black (or the last-known screen in faded grey, depending on graphics settings) screens (because it doesn't have any up to date information). Whereas in XP, it leaves the old content up, but dragging a window over it causes shadows of the window to be displayed on the screen, because the lower window is not updating.
Update:
How do you fix it? Well, there's a bunch of different things, but if you have a method that takes a very long time:
private void SomethingThatTakesAReallyLongTime()
{
System.Threading.Thread.Sleep(30000);
}
Your event handler can look like this:
private void button1_Click(object sender, EventArgs e)
{
((Action)SomethingThatTakesAReallyLongTime).BeginInvoke(null);
}
This may not be a good idea in many cases, but it's a simple example of things you can try.
You are tying up the UI thread (main thread) for an extended period of time likely because the operation is intensive (either CPU or disk). Try moving the intensive operation (say reading file) into a second thread. This will keep the main thread (one w/ UI) responsive to the user and OS.
There are numerous methods to accomplish this. Using a BackgroundWorker is the simplest to implement. This should get you started:
http://msdn.microsoft.com/en-us/library/cc221403(VS.95).aspxr
Esesentially you will:
Create a backgroundWorker
Create an event handler for the DoWork event and wire it to DoWork.
Place the CPU intensive operation inside the DoWork event handler.
Call the RunAsync() method of the backgroundWorker (which will keep off DoWork event)
You can get more complex with providing progress and allowing user to cancel. Here is an example of loading large file:
http://msdn.microsoft.com/en-us/library/ms229675.aspx
This happens when your main thread is working on a relatively long-running task and therefore cannot repaint the screen. Thy using a worker thread to load the csv (for this example) and you shouldn't have this problem.
More than likely, it's happening because you're trying to execute a long running process on the UI thread (which blocks the UI thread so that it can't redraw the form).
You should use some form of Threading to start the long running process on a separate thread so that the UI can continue to function.
I am writing a small test application to test a communication interface. The communication interface is written in C++ (a DLL) and the test application using C#. The communication interface in turn talks to a low level hardware stack which uses windows messages to transmit and receive data. In order to achieve this, the commuication interface DLL creates an invisible child window whose parent is the C# test application window. The sequence to talk to the hardware is as follows :
Initialize the communication library. This step expects the main window handle and application instance which is passed to the low level stack for windows messaging.
Connect using the device address
Read/Write
Close
Deinitialize the communication library.
Now in the 2nd step, the DLL creates an invisible window to communicate with the low level hardware stack. Since the 2nd step is a blocking call, I want my UI to be responsive during this time in case it takes a long time to connect. Therefore, I try to connect asynchronously using a thread or a BeginInvoke call. But I observe that after the connection is established, the application window hangs as long as the child window exists. The child window seems to block all incoming messages to the main window. This seems to be because the child window gets created in another thread.
But I dont want want the connect to be in the main thread as it hangs the UI.
I would welcome any ideas on how to avoid this problem ? Thanks in advance.
-Harish
All communication with a window handle must be done on the thread this handle was created on. This probably means that all calls to the DLL should be done on the secondary thread.
You can try the following:
Before initializing the DLL, start a background thread;
On that thread, create a WinForms window you do not show. You can do this like this:
-
public static Form BackgroundForm;
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
new Thread(new ThreadStart(Secondary)).Start();
Application.Run(new MainForm());
}
static void Secondary()
{
BackgroundForm = new Form();
// Calling Handle creates the system HWND. You do not have to call Show
// or something similar on this Form to make the handle available or use
// Invoke or BeginInvoke.
var handle = BackgroundForm.Handle;
// Initialize the DLL here with the handle.
Application.Run();
// Unintialize the DLL.
}
Then, initialize the DLL with the handle you got from the background form;
When you need to do calls to the DLL, do this using Invoke and BeginInvoke to this background form;
Once it's time to shut down your application, do an Application.ExitThread() through a Invoke or BeginInvoke.
The problem you are seeing with the main form being blocked, is probably because the child window created in the DLL has the main form's handle as it's parent Window, but that's just a guess. This should probably also be solved using this system.
I have multiple forms that popup during an intensive operation. For example, when a form popups asking user for something, and the user clicks OK, the form's graphics stay on the main screen, even though it is closed. How can I make it so that these graphics disappear completely?
I would recommend performing the heavy work in the background (using a BackgroundWorker for instance), so that the GUI thread is not blocked. That way, the forms will be able to peform screen updates while the work is going on.
It sounds like perhaps you are doing intensive processing on your main thread, which is the thread that processes events like painting windows. Instead you should spawn a separate thread for doing your computations/tasks so that your main thread can continue.
Alternatively you can call DoEvents() periodically while doing your processing to allow the form to refresh, but using DoEvents is kind of a cludge in my opinion.
You can call the Refresh() method on the main screen form, which will force a graphics repaint.