I am showing a splash form by starting a new thread immediately before running my main form.
In the method that is run by this thread, I am using Application.Run as shown in Option 1 below. Is this a correct way of doing this, or are there problems waiting for me becaue I have called Application.Run twice? An alternative is Option 2, also shown below where I call .ShowDialog() to display the form.
The splash form itself closes after a specified time, controlled within the form itself, and both options appear to work well.
So my question is: Which is preferred - Option 1 or Option 2? If you could give specific reasons for one or the other that would be great.
Thanks.
Snippet of Main:
// Run splash screen thread.
Thread splash = new Thread(new ThreadStart(ShowSplash));
splash.Start();
// Run main application.
Application.Run(new MainForm());
Show splash form option 1:
static void ShowSplash()
{
Application.Run(new SplashForm());
}
Show splash form option 2:
static void ShowSplash()
{
using (SplashForm splash = new SplashForm())
{
splash.ShowDialog();
}
}
Option 2 will probably run into trouble because then you are using the same Mesageloop as the MainForm but from another thread.
Option 1 is fine.
I realize that this may be an unusual viewpoint but have you considered not using a Splash screen and instead showing the information on the 'welcome page' or 'help > about' screen instead?
There are a handful of reasons to do this:
Unless you get into multi-threading, a Splash Screen may not repaint properly if some alert/msgbox pops up over the top of it, negating the benefit of the splash screen entirely.
Splash screens that show 'you have plugins x, y and z' installed can't really tell this until that information has been loaded up. By the time this info is loaded, your app is ready to go, so you'll either close the splash screen or it'll be in the way of the user.
If I look away and miss the splash screen, I'll miss whatever information you're telling me. If 'License expires in 3 days' is part of that information, and today is Friday, that means I won't realise that on Monday, I can't use the app. Obscure, but I've seen it.
Related
I'll try to make this question as uncomplicated as possible. I have three forms frm_Splash which checks for updates; frm_Wizard which completes first-run setup; and frm_Main which is the main program. These forms' relationships are diagrammed below:
Right now in Program.cs I have this code:
public static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new frm_Main());
}
which sets frm_Main as my main form. What is best practice to handle frm_Wizard and frm_Main? I do not want them to load before I have finished updates (if there are any).
After this, if the wizard needs to be shown, the splash screen should disappear and the wizard should appear.
Finally, once all the updates and first-time setup is done, the main form shows (but not before). How do I accomplish all this?
Some things I know:
I know I can set frm_Splash to be the startup form, but then when I close it, the whole program closes.
I could also hide forms, but doesn't that waste memory with forms
sitting in the background?
And finally, I'm looking for some general code or concepts of how to do this. I already am familiar with c# coding, so you don't need to code everything. I'm merely looking for a best practice to handle this. i.e. Should I be coding in the Program.cs, or each form's load event? If there's anything unclear about my question, please let me know before you downvote! Thank you.
One thing to note is that you do not need to use Application.Run to launch a form. So you can just create a 3 step process in your Main function:
public static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//Show splash form (which checks for updates)
FormSplash splash = new FormSplash();
splash.ShowDialog();//will wait until splash closed
//check if first run and show if needed
if(IsFirstRun())
{
FormWizard wizard = new FormWizard();
wizard.ShowDialog();//will wait until wizard is closed
}
//Finally, run your application as normal
Application.Run(new frm_Main());
}
NOTE: I am not aware of the benefits of using Application.Run to launch you main form, I assume one of them is allowing access to Application state functions (such as Exit), but I can say I have used this technique for a splash screen in the past, and have not had any issues with doing it this way
In my application it takes some time to loan my initial screen(1-2 mins). Since it has so many controls to be filled by Database.
So I need to have a splash screen, it will load(probably with a progress bar) and stays while main form loads. Means in background I need to load main form (better with out showing)
Only main window finishes loading, it notifies to splash, the splash will go off and main will be visible.
I tried to achieve above with several way but no success.
Any one can help me ?
look at this Splash screen
and this Splash screen class
FormSplash splash = new FormSplash();
this.BeginInvoke(
new MethodInvoker(
() =>
{
splash.Show();
}
)
);
// main form code here
// at end of loading code
splash.Close();
The above code belongs in Form_Load of the main form.
There are a couple of good approaches discussed at Show a splash screen at once (in fact to me this and the other question appear to be duplicates).
The best way and using the API is
SplashScreen splash = new SplashScreen("splashscreen.jpg");
splash.Show(false);
splash.Close(TimeSpan.FromMilliseconds(2));
InitializeComponent();
I have a C# application which runs into trouble when it comes to multi-threads / backgroundworkers when I'm using a splash screen before I load the main window.
my code look something like this:
[STAThread]
private static void Main()
{
.. do some stuff
ShowSplash(); // where i show a splash screen and load some stuff
...
As the last step of ShowSplash, I do the following:
new MyCabApplication<MyMainWorkItem, MDIParentForm>().Run(); -- where i load the form through cab.
The problem is that when I do that I get the following exception:
Starting a second message loop on a single thread is not a valid operation. Use Form.ShowDialog instead
Any idea what can I do?
Here is my showsplash function:
private static DialogResult ShowSplash(AutoResetEvent controller)
{
// create and register splash screen
splashScreen = new PointSplashScreen();
Application.Run(splashScreen);
return DialogResult.OK;
}
Two solutions:
Instead of using Application.Run, just create a new instance of the form and then call ShowDialog. Move new MyCabApplication<MyMainWorkItem, MDIParentForm>().Run(); outside of the Splash Screen after the call to ShowDialog(). You can check properties of the Splash screen if this code should not always be run.
Instead of using Application.Run(Form), use Application.Run(ApplicationContext). You will need to create a new ApplicationContext and move your code there.
Solution 1 is easier.
It sounds like MyCabApplication extends Application. The Run method starts a WinForm application by starting a message loop that handles window messages.
Because you are already showing UI, there is already a message loop running, so you cannot start another. To get your main form to show up, make a new instance of it and call Show():
var form = new MainForm();
form.Show();
I'm having some serious issues with a WinForm application that I'm working on.
Currently, I'm using Form1.ShowDialog(); to display a form. This code is contained in a background worker that looks for changes in a database. Using Form1.ShowDialog(); only allows 1 form to open at a time, even if there are multiple changes to the database. What I want to have happen is for multiple forms to open at once if there is more than one change in my database.
When I use Form1.Show();, the application blows up. For some reason, the Show() method makes the forms not display properly (all the elements in the form are missing).
Is there anything I can do to make my code work the way I want it to?
Edit: here's a code snippet
//result is a linq result
foreach (var row in result)
{
Form1 Form = new Form1();
Form.ShowDialog();
}
After a first look, I can tell you this:
Showdialog can't work the way you intend: this very method makes the owner inactive until the dialog is closed. In your case, the loop will pause at the first showdialog, then resume when you close the form, opening a new one and so on until the loop is finished.
As for the "show" problem, creating empty forms, I need more information. The rest of the code and the exception(s) you're getting.
Two points from the top of my head:
1) To open more then one form , use non modal (modeless) method (i think
the show() method). see for example http://msdn.microsoft.com/en-us/library/39wcs2dh.aspx
2) I am not sure you can call UI related method from a non UI thread. You might want to send an event to your UI thread from the worker thread and the UI thread will call the show method
How can I create a Popup balloon like you would see from Windows Messenger or AVG or Norton or whomever?
I want it to show the information, and then slide away after a few seconds.
Edit: It needs to be blocking like Form.ShowDialog() because the program exits after displaying the notification
You can use the notifyIcon control that's part of .NET 2.0 System.Windows.Forms. That allows you to place an icon for your application in the System Tray. Then, you can call the ShowBalloonTip(int timeOut) method on that. Be sure however to first set the text, and icon properties on the notifyIcon for it to work. Small code sample:
private void button1_Click(object sender, EventArgs e)
{
this.notifyIcon1.BalloonTipText = "Whatever";
this.notifyIcon1.BalloonTipTitle = "Title";
this.notifyIcon1.Icon = new Icon("icon.ico");
this.notifyIcon1.Visible = true;
this.notifyIcon1.ShowBalloonTip(3);
}
EDIT: Ok, so notifyIcon won't work for you. My second suggestion would then be to create your own control for this. Actually, I would use a form. A simple form, with no borders, and no control box and just have a timer running so you can set the Opacity for fade in/out. Then, you can easily get the bottom right of the screen using the Rectangle Screen.PrimaryScreen.WorkingArea. Then just show your form at that position.
Don't create a modal (blocking) balloon. Please. A big part of the design of these UIs is that they are not dialogs: they're transient, potentially non-interactive elements, intended to provide incidental information to a user without necessarily interrupting their workflow. A balloon that steals focus and blocks user input would be irritating at best - if you need a dialog, then use a dialog.
The .NET 1.1 Visual Basic Power Pack had a toaster control.