How can I display the Wait/Busy Cursor (usually the hourglass) to the user to let them know the program is doing something?
You can use Cursor.Current.
// Set cursor as hourglass
Cursor.Current = Cursors.WaitCursor;
// Execute your time-intensive hashing code here...
// Set cursor as default arrow
Cursor.Current = Cursors.Default;
However, if the hashing operation is really lengthy (MSDN defines this as more than 2-7 seconds), you should probably use a visual feedback indicator other than the cursor to notify the user of the progress. For a more in-depth set of guidelines, see this article.
Edit:
As #Am pointed out, you may need to call Application.DoEvents(); after Cursor.Current = Cursors.WaitCursor; to ensure that the hourglass is actually displayed.
Actually,
Cursor.Current = Cursors.WaitCursor;
temporarily sets the Wait cursor, but doesn’t ensure that the Wait cursor shows until the end of your operation. Other programs or controls within your program can easily reset the cursor back to the default arrow as in fact happens when you move mouse while operation is still running.
A much better way to show the Wait cursor is to set the UseWaitCursor property in a form to true:
form.UseWaitCursor = true;
This will display wait cursor for all controls on the form until you set this property to false.
If you want wait cursor to be shown on Application level you should use:
Application.UseWaitCursor = true;
Building on the previous, my preferred approach (since this is a frequently performed action) is to wrap the wait cursor code in an IDisposable helper class so it can be used with using() (one line of code), take optional parameters, run the code within, then clean up (restore cursor) afterwards.
public class CursorWait : IDisposable
{
public CursorWait(bool appStarting = false, bool applicationCursor = false)
{
// Wait
Cursor.Current = appStarting ? Cursors.AppStarting : Cursors.WaitCursor;
if (applicationCursor) Application.UseWaitCursor = true;
}
public void Dispose()
{
// Reset
Cursor.Current = Cursors.Default;
Application.UseWaitCursor = false;
}
}
Usage:
using (new CursorWait())
{
// Perform some code that shows cursor
}
It is easier to use UseWaitCursor at the Form or Window level.
A typical use case can look like below:
private void button1_Click(object sender, EventArgs e)
{
try
{
this.Enabled = false;//optional, better target a panel or specific controls
this.UseWaitCursor = true;//from the Form/Window instance
Application.DoEvents();//messages pumped to update controls
//execute a lengthy blocking operation here,
//bla bla ....
}
finally
{
this.Enabled = true;//optional
this.UseWaitCursor = false;
}
}
For a better UI experience you should use Asynchrony from a different thread.
My approach would be to make all the calculations in a background worker.
Then change the cursor like this:
this.Cursor = Cursors.Wait;
And in the thread's finish event restore the cursor:
this.Cursor = Cursors.Default;
Note, this can also be done for specific controls, so the cursor will be the hourglass only when the mouse is above them.
For Windows Forms applications an optional disabling of a UI-Control can be very useful. So my suggestion looks like this:
public class AppWaitCursor : IDisposable
{
private readonly Control _eventControl;
public AppWaitCursor(object eventSender = null)
{
_eventControl = eventSender as Control;
if (_eventControl != null)
_eventControl.Enabled = false;
Application.UseWaitCursor = true;
Application.DoEvents();
}
public void Dispose()
{
if (_eventControl != null)
_eventControl.Enabled = true;
Cursor.Current = Cursors.Default;
Application.UseWaitCursor = false;
}
}
Usage:
private void UiControl_Click(object sender, EventArgs e)
{
using (new AppWaitCursor(sender))
{
LongRunningCall();
}
}
Okey,Other people's view are very clear, but I would like to do some added, as follow:
Cursor tempCursor = Cursor.Current;
Cursor.Current = Cursors.WaitCursor;
//do Time-consuming Operations
Cursor.Current = tempCursor;
OK so I created a static async method. That disabled the control that launches the action and changes the application cursor. It runs the action as a task and waits for to finish. Control returns to the caller while it waits. So the application remains responsive, even while the busy icon spins.
async public static void LengthyOperation(Control control, Action action)
{
try
{
control.Enabled = false;
Application.UseWaitCursor = true;
Task doWork = new Task(() => action(), TaskCreationOptions.LongRunning);
Log.Info("Task Start");
doWork.Start();
Log.Info("Before Await");
await doWork;
Log.Info("After await");
}
finally
{
Log.Info("Finally");
Application.UseWaitCursor = false;
control.Enabled = true;
}
Here's the code form the main form
private void btnSleep_Click(object sender, EventArgs e)
{
var control = sender as Control;
if (control != null)
{
Log.Info("Launching lengthy operation...");
CursorWait.LengthyOperation(control, () => DummyAction());
Log.Info("...Lengthy operation launched.");
}
}
private void DummyAction()
{
try
{
var _log = NLog.LogManager.GetLogger("TmpLogger");
_log.Info("Action - Sleep");
TimeSpan sleep = new TimeSpan(0, 0, 16);
Thread.Sleep(sleep);
_log.Info("Action - Wakeup");
}
finally
{
}
}
I had to use a separate logger for the dummy action (I am using Nlog) and my main logger is writing to the UI (a rich text box). I wasn't able to get the busy cursor show only when over a particular container on the form (but I didn't try very hard.) All controls have a UseWaitCursor property, but it doesn't seem have any effect on the controls I tried (maybe because they weren't on top?)
Here's the main log, which shows things happening in the order we expect:
16:51:33.1064 Launching lengthy operation...
16:51:33.1215 Task Start
16:51:33.1215 Before Await
16:51:33.1215 ...Lengthy operation launched.
16:51:49.1276 After await
16:51:49.1537 Finally
With the class below you can make the suggestion of Donut "exception safe".
using (new CursorHandler())
{
// Execute your time-intensive hashing code here...
}
the class CursorHandler
public class CursorHandler
: IDisposable
{
public CursorHandler(Cursor cursor = null)
{
_saved = Cursor.Current;
Cursor.Current = cursor ?? Cursors.WaitCursor;
}
public void Dispose()
{
if (_saved != null)
{
Cursor.Current = _saved;
_saved = null;
}
}
private Cursor _saved;
}
Use this with WPF:
Cursor = Cursors.Wait;
// Your Heavy work here
Cursor = Cursors.Arrow;
You can use:
Mouse.OverrideCursor = Cursors.Wait;
&&
Mouse.OverrideCursor = Cursors.Arrow;
Related
Here's the thing, I have started with C# and I want to do something like this:
I have a Windows Form Application with one button and the picturebox.
Clicking on a button should result in turning property "Running" on true/false, by the actual state. That is done.
Also, it should result into turning on the script that will be doing constantly a job as the program runs. This "job" will be described in Run() method. And I want this method to be executed only when Running == true, in moment it becomes false, the method should end.
So I decided put it into the thread and in the method where I switch between Running = true and Running = false, I try to start the thread and abort it.
Why do I want to do this? Because I want to be able to turn program working on and off by the button I mentioned at the beginning.
This is what I came up with:
Thread thProgram;
public Form1()
{
InitializeComponent();
thProgram = new Thread(new ThreadStart(this.Run));
}
private bool Running = false;
public void Run()
{
int i = 0;
while(this.Running)
{
i++;
}
MessageBox.Show("Terminated");
}
// handling bot activation button (changing color of a pictureBox1), switching this.Running property
private void button1_Click(object sender, EventArgs e)
{
if(this.Running)
{
thProgram.Abort();
pictureBox1.BackColor = Color.Red;
this.Running = false;
}
else
{
thProgram.Start();
pictureBox1.BackColor = Color.Lime;
this.Running = true;
}
}
I can click the button exactly twice, and it appears that everything is all right... but when I click it for the third time, error pops up:
(it highlights the line "thProgram.Start();"
An unhandled exception of type 'System.Threading.ThreadStateException' occurred in mscorlib.dll
Additional information: Thread is running or terminated; it cannot restart.
Thanks in advance for any help you are able to provide me with.
The exception is Self-explaining
When you press the button for the first time, the thread starts and falls into its main loop.
The second button press aborts the thread (which is always a bad idea. That flag you used is enough) and the thread terminates.
The third button press? From MSDN documentation for Thread.Start() :
Once the thread terminates, it cannot be restarted with another call to Start.
To freeze a thread without terminating it, I suggest using AutoResetEvent:
public Form1()
{
InitializeComponent();
thProgram = new Thread(new ThreadStart(this.Run));
}
private bool Running = false;
private AutoResetEvent ThreadHandle = new AutoResetEvent(false);
public void Run()
{
int i = 0;
while(true)
{
ThreadHandle.WaitOne();
i++;
}
MessageBox.Show("Terminated");
}
// handling bot activation button (changing color of a pictureBox1), switching this.Running property
private void button1_Click(object sender, EventArgs e)
{
if(this.Running)
{
thProgram.Abort();
pictureBox1.BackColor = Color.Red;
this.ThreadHandle.Reset();
this.Running = false;
}
else
{
thProgram.Start();
pictureBox1.BackColor = Color.Lime;
this.ThreadHandle.Set();
this.Running = true;
}
}
I'm having a problem where I cannot await an asynchronous function inside of the FormClosing event which will determine whether the form close should continue. I have created a simple example that prompts you to save unsaved changes if you close without saving (much like with notepad or microsoft word). The problem I ran into is that when I await the asynchronous Save function, it proceeds to close the form before the save function has completed, then it comes back to the closing function when it is done and tries to continue. My only solution is to cancel the closing event before calling SaveAsync, then if the save is successful it will call the form.Close() function. I'm hoping there is a cleaner way of handling this situation.
To replicate the scenario, create a form with a text box (txtValue), a checkbox (cbFail), and a button (btnSave). Here is the code for the form.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace TestZ
{
public partial class Form1 : Form
{
string cleanValue = "";
public Form1()
{
InitializeComponent();
}
public bool HasChanges()
{
return (txtValue.Text != cleanValue);
}
public void ResetChangeState()
{
cleanValue = txtValue.Text;
}
private async void btnSave_Click(object sender, EventArgs e)
{
//Save without immediate concern of the result
await SaveAsync();
}
private async Task<bool> SaveAsync()
{
this.Cursor = Cursors.WaitCursor;
btnSave.Enabled = false;
txtValue.Enabled = false;
cbFail.Enabled = false;
Task<bool> work = Task<bool>.Factory.StartNew(() =>
{
//Work to do on a background thread
System.Threading.Thread.Sleep(3000); //Pretend to work hard.
if (cbFail.Checked)
{
MessageBox.Show("Save Failed.");
return false;
}
else
{
//The value is saved into the database, mark current form state as "clean"
MessageBox.Show("Save Succeeded.");
ResetChangeState();
return true;
}
});
bool retval = await work;
btnSave.Enabled = true;
txtValue.Enabled = true;
cbFail.Enabled = true;
this.Cursor = Cursors.Default;
return retval;
}
private async void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (HasChanges())
{
DialogResult result = MessageBox.Show("There are unsaved changes. Do you want to save before closing?", "Unsaved Changes", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
if (result == System.Windows.Forms.DialogResult.Yes)
{
//This is how I want to handle it - But it closes the form while it should be waiting for the Save() to complete.
//bool SaveSuccessful = await Save();
//if (!SaveSuccessful)
//{
// e.Cancel = true;
//}
//This is how I have to handle it:
e.Cancel = true;
bool SaveSuccessful = await SaveAsync();
if (SaveSuccessful)
{
this.Close();
}
}
else if (result == System.Windows.Forms.DialogResult.Cancel)
{
e.Cancel = true;
}
//If they hit "No", just close the form.
}
}
}
}
Edit 05/23/2013
Its understandable that people would ask me why I would be trying to
do this. The data classes in our libraries will often have Save,
Load, New, Delete functions that are designed to be run asynchronously
(See SaveAsync as an example). I do not actually care that much about
running the function asynchronously in the FormClosing Event specifically. But if
the user wants to save before closing the form, I need it to wait and
see if the save succeds or not. If the save fails, then I want it to
cancel the form closing event. I'm just looking for the cleanest way to
handle this.
The best answer, in my opinion, is to cancel the Form from closing. Always. Cancel it, display your dialog however you want, and once the user is done with the dialog, programatically close the Form.
Here's what I do:
async void Window_Closing(object sender, CancelEventArgs args)
{
var w = (Window)sender;
var h = (ObjectViewModelHost)w.Content;
var v = h.ViewModel;
if (v != null &&
v.IsDirty)
{
args.Cancel = true;
w.IsEnabled = false;
// caller returns and window stays open
await Task.Yield();
var c = await interaction.ConfirmAsync(
"Close",
"You have unsaved changes in this window. If you exit they will be discarded.",
w);
if (c)
w.Close();
// doesn't matter if it's closed
w.IsEnabled = true;
}
}
It is important to note the call to await Task.Yield(). It would not be necessary if the async method being called always executed asynchronously. However, if the method has any synchronous paths (ie. null-check and return, etc...) the Window_Closing event will never finish execution and the call to w.Close() will throw an exception.
Dialogs handle messages while still keeping the current method on the stack.
You could show a "Saving..." Dialog in your FormClosing handler, and run the actual saving-operation in a new task, which programmatically closes the dialog once it's done.
Keep in mind that SaveAsync is running in a non-UI Thread, and needs to marshal any access UI elements via Control.Invoke (see call to decoy.Hide below). Best would probably be to extract any data from controls beforehand, and only use variables in the task.
protected override void OnFormClosing(FormClosingEventArgs e)
{
Form decoy = new Form()
{
ControlBox = false,
StartPosition = FormStartPosition.CenterParent,
Size = new Size(300, 100),
Text = Text, // current window caption
};
Label label = new Label()
{
Text = "Saving...",
TextAlign = ContentAlignment.MiddleCenter,
Dock = DockStyle.Fill,
};
decoy.Controls.Add(label);
var t = Task.Run(async () =>
{
try
{
// keep form open if saving fails
e.Cancel = !await SaveAsync();
}
finally
{
decoy.Invoke(new MethodInvoker(decoy.Hide));
}
});
decoy.ShowDialog(this);
t.Wait(); //TODO: handle Exceptions
}
You can't keep your form from closing with async/await. And you can get strange results.
What I would do is creating a Thread and setting its IsBackground property to false (which is false by default) to keep the process alive while form is closing.
protected override void OnClosing(CancelEventArgs e)
{
e.Cancel = false;
new Thread(() => {
Thread.Sleep(5000); //replace this line to save some data.....
MessageBox.Show("EXITED");
}).Start();
base.OnClosing(e);
}
I had a similar issue when I tried to handle all of the close event async. I believe it is because there is nothing to block the main thread from moving forward with the actual FormClosingEvents. Just put some inline code after the await and it solves the problem. In my case I save the current state no matter the response (while waiting for the response). You could easily have the task return a current state ready to be saved appropriately once the user responds.
This worked for me: Spin off task, ask exit confirmation, await task, some inline code.
Task myNewTask = SaveMyCurrentStateTask(); //This takes a little while so I want it async in the background
DialogResult exitResponse = MessageBox.Show("Are you sure you want to Exit MYAPPNAME? ", "Exit Application?", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2);
await myNewTask;
if (exitResponse == DialogResult.Yes)
{
e.Cancel = false;
}
else
{
e.Cancel = true;
}
I needed to abort closing the form if an exeption was raised during the execution of an async method.
I'm actually using a Task.Run with .Wait()
private void Example_FormClosing(object sender, FormClosingEventArgs e)
{
try
{
Task.Run(async () => await CreateAsync(listDomains)).Wait();
}
catch (Exception ex)
{
MessageBox.Show($"{ex.Message}", "Attention", MessageBoxButtons.OK, MessageBoxIcon.Error);
e.Cancel = true;
}
}
Why does asynchronous behavior have to be involved? It sounds like something that has to happen in a linear fashion.. I find the simplest solution is usually the right one.
Alternatively to my code below, you could have the main thread sleep for a second or two, and have the async thread set a flag in the main thread.
void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (HasChanges())
{
DialogResult result = MessageBox.Show("There are unsaved changes. Do you want to save before closing?", "Unsaved Changes", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
if (result == DialogResult.Yes)
{
e.Cancel = true;
if(!Save())
{
MessageBox.Show("Your work could not be saved. Check your input/config and try again");
e.Cancel = true;
}
}
else if (result == DialogResult.Cancel)
{
e.Cancel = true;
} } }
I've an existing WPF application, which has several sections. Every section is a UserControl, that implements an interface.
The interface specify two methods: void LoadData([...]) and bool UnloadData().
Those method are called by the UI thread, so we need to do our work in backgroundworker if it's time consuming.
No problems with LoadData since we can update the UI asynchronously. The problem is with UnloadData().
This should return if we can really leave the current view.
This is computed with the current status of data(Saved/modified/Invalid):
Saved return true,
Invalid asks if you want to stay to save some
correct data or leave without saving
Modified tell you that you can
either cancel your change(return true), either continue to
edit(return false), either save you current data(return true)
The problem is with the "Modified -> Save". This is a time consuming method, so to respect the philosophy of the application, we should run this in a background thread(with a busy indicator).
But if we just launch the thread and go to the next section, it will return "true" to the method call, and we will directly launch the next view.
In my case, loading the next view before our local data is saved can be a problem.
So:
Is there a way to wait on the background thread to finish before returning "true", WITHOUT blocking the UI?
public bool UnloadData(){
if(...){
LaunchMyTimeConsumingMethodWithBackgroundWorker();
return true;//Only when my time consuming method ends
}
//[...]
}
Important EDIT
Maybe I wasn't clear enought: I know how to use a BackgroundWorker, or TPL. My problem is that the parent class(the one which call the UnloadData()" is a class that I cannot edit(for multiple reasons: It's in another DLL that will not be reloaded, it already works with 70+ userControls, all in separate projects(dll), loaded by reflection.
This wasn't my choice, I don't find it good, but I've to deal with it now. I'm mostly looking for way to make my method wait on the return of my method. I'm not sure if it is possible. But I'm looking for a workaround, it will spare me weeks of works.
Ok now I'm excited, because I think I may have discovered something on my own...
So, what you do is this: You create a DispatcherFrame, push that frame onto the Dispatcher, and in the RunWorkerCompleted you set the Continue of the Frame to false.
This is the code so far:
public void Function()
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += TimeConsumingFunction;
var frame = new DispatcherFrame();
worker.RunWorkerCompleted += (sender, args) =>
{
frame.Continue = false;
};
worker.RunWorkerAsync();
Dispatcher.PushFrame(frame);
}
private void TimeConsumingFunction(object sender, DoWorkEventArgs doWorkEventArgs)
{
Console.WriteLine("Entering");
for (int i = 0; i < 3; i++)
{
Thread.Sleep(1000);
}
Console.WriteLine("Exiting");
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
Function();
Console.WriteLine("Returns");
}
You should implement a dependency property "IsBusy" of type bool, that you set to TRUE before starting the BackgoundWorker, and then to FALSE when the work is complete.
On the UI, you bind to that property whatever functionality you want disabled during the processing(like the button for loading the next view, etc.); or maybe showing a "Cancel" button.
You should not "wait" for the operation to complete, you can retrieve the result in an additional variable, that the BackgroundWorker will set:
BackgroundWorker _bw;
bool _returnValue = false;
private void button_Click(object sender, RoutedEventArgs e)
{ // if starting the processing by clicking a button
_bw = new BackgroundWorker();
IsBusy = true;
_bw.DoWork += new DoWorkEventHandler(_bw_DoWork);
_bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_bw_RunWorkerCompleted);
_bw.RunWorkerAsync();
}
void _bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
IsBusy = false;
// retrieve the result of the operation in the _returnValue variable
}
void _bw_DoWork(object sender, DoWorkEventArgs e)
{
_returnValue = UnloadData();
}
private bool UnloadData()
{
if (...)
{
LaunchTimeConsumingMethod();
return true;
}
else
return false;
//etc ...
}
public bool IsBusy
{
get { return (bool)GetValue(IsBusyProperty); }
set { SetValue(IsBusyProperty, value); }
}
// Using a DependencyProperty as the backing store for IsBusy. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsBusyProperty =
DependencyProperty.Register( ... )
You may be able to try using the new "await" features of .NET 4.5.
The await keyword allows you to await the completion of a Task object, without blocking the UI.
Try this modification:
public async bool UnloadData()
{
if(...)
{
await Task.Factory.StartNew(() =>
{
LaunchMyTimeConsumingMethod();
});
return true;//Only when my time consuming method ends
}
//[...]
}
Treat UnloadData as a async operation and let the async/await features handle both the case when it completes synchronously and when it needs to complete asynchronously:
public async Task<bool> UnloadData(){
if(...){
// The await keyword will segment your method execution and post the continuation in the UI thread
// The Task.Factory.StartNew will run the time consuming method in the ThreadPool
await Task.Factory.StartNew(()=>LaunchMyTimeConsumingMethodWithBackgroundWorker());
// The return statement is the continuation and will run in the UI thread after the consuming method is executed
return true;
}
// If it came down this path, the execution is synchronous and is completely run in the UI thread
return false;
}
private async void button_Click(object sender, RoutedEventArgs e)
{
// Put here your logic to prevent user interaction during the operation's execution.
// Ex: this.mainPanel.IsEnabled = false;
// Or: this.modalPanel.Visibility = Visible;
// etc
try
{
bool result = await this.UnloadData();
// Do whatever with the result
}
finally
{
// Reenable the user interaction
// Ex: this.mainPanel.IsEnabled = true;
}
}
EDIT
If you can't modify the UnloadData, then just execute it on the ThreadPool, as #BTownTKD noted:
private async void button_Click(object sender, RoutedEventArgs e)
{
// Put here your logic to prevent user interaction during the operation's execution.
// Ex: this.mainPanel.IsEnabled = false;
// Or: this.modalPanel.Visibility = Visible;
// etc
try
{
// The await keyword will segment your method execution and post the continuation in the UI thread
// The Task.Factory.StartNew will run the time consuming method in the ThreadPool, whether it takes the long or the short path
bool result = await The Task.Factory.StartNew(()=>this.UnloadData());
// Do whatever with the result
}
finally
{
// Reenable the user interaction
// Ex: this.mainPanel.IsEnabled = true;
}
}
You probably should use TPL if your framework version is 4.0:
var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext(); // this will work only if you're running this code from UI thread, for example, by clicking a button
Task.Factory.StartNew(() => UnloadData()).ContinueWith(t => /*update ui using t.Result here*/, uiScheduler);
Hope this helps.
You have to implement a callback function (RunWorkerCompleted), this is called when the background worker finishes.
Check out an example here:
http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx
I need to show splash screen on my application start for few seconds. Does anybody know how to implement this?
Will be much appreciate for the help.
First, create your splash screen as a borderless, immovable form with your image on it, set to initially display at the center of the screen, colored the way you want. All of this can be set from within the designer; specifically, you want to:
Set the form's ControlBox, MaximizeBox, MinimizeBox and ShowIcon properties to "False"
Set the StartPosition property to "CenterScreen"
Set the FormBorderStyle property to "None"
Set the form's MinimumSize and MaximumSize to be the same as its initial Size.
Then, you need to decide where to show it and where to dismiss it. These two tasks need to occur on opposite sides of the main startup logic of your program. This could be in your application's main() routine, or possibly in your main application form's Load handler; wherever you're creating large expensive objects, reading settings from the hard drive, and generally taking a long time to do stuff behind the scenes before the main application screen displays.
Then, all you have to do is create an instance of your form, Show() it, and keep a reference to it while you do your startup initialization. Once your main form has loaded, Close() it.
If your splash screen will have an animated image on it, the window will need to be "double-buffered" as well, and you will need to be absolutely sure that all initialization logic happens outside the GUI thread (meaning you cannot have your main loading logic in the mainform's Load handler; you'll have to create a BackgroundWorker or some other threaded routine.
Here are some guideline steps...
Create a borderless form (this will be your splash screen)
On application start, start a timer (with a few seconds interval)
Show your Splash Form
On Timer.Tick event, stop timer and close Splash form - then show your main application form
Give this a go and if you get stuck then come back and ask more specific questions relating to your problems
simple and easy solution to create splash screen
open new form use name "SPLASH"
change background image whatever you want
select progress bar
select timer
now set timer tick in timer:
private void timer1_Tick(object sender, EventArgs e)
{
progressBar1.Increment(1);
if (progressBar1.Value == 100) timer1.Stop();
}
add new form use name "FORM-1"and use following command in FORM 1.
note: Splash form works before opening your form1
add this library
using System.Threading;
create function
public void splash()
{
Application.Run(new splash());
}
use following command in initialization like below.
public partial class login : Form
{
public login()
{
Thread t = new Thread(new ThreadStart(splash));
t.Start();
Thread.Sleep(15625);
InitializeComponent();
enter code here
t.Abort();
}
}
http://solutions.musanitech.com/c-create-splash-screen/
I wanted a splash screen that would display until the main program form was ready to be displayed, so timers etc were no use to me. I also wanted to keep it as simple as possible.
My application starts with (abbreviated):
static void Main()
{
Splash frmSplash = new Splash();
frmSplash.Show();
Application.Run(new ReportExplorer(frmSplash));
}
Then, ReportExplorer has the following:
public ReportExplorer(Splash frmSplash)
{
this.frmSplash = frmSplash;
InitializeComponent();
}
Finally, after all the initialisation is complete:
if (frmSplash != null)
{
frmSplash.Close();
frmSplash = null;
}
Maybe I'm missing something, but this seems a lot easier than mucking about with threads and timers.
create splash
private void timer1_Tick(object sender, EventArgs e)
{
counter++;
progressBar1.Value = counter *5;
// label2.Text = (5*counter).ToString();
if (counter ==20)
{
timer1.Stop();
this.Close();
}
}
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.SystemColors.GradientInactiveCaption;
this.ClientSize = new System.Drawing.Size(397, 283);
this.ControlBox = false;
this.Controls.Add(this.label2);
this.Controls.Add(this.progressBar1);
this.Controls.Add(this.label1);
this.ForeColor = System.Drawing.SystemColors.ControlLightLight;
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.Name = "Splash";
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.ResumeLayout(false);
this.PerformLayout();
Then in your application
sp = new Splash();
sp.ShowDialog();
The other answers here cover this well, but it is worth knowing that there is built in functionality for splash screens in Visual Studio: If you open the project properties for the windows form app and look at the Application tab, there is a "Splash screen:" option at the bottom. You simply pick which form in your app you want to display as the splash screen and it will take care of showing it when the app starts and hiding it once your main form is displayed.
You still need to set up your form as described above (with the correct borders, positioning, sizing etc.)
None of the other answers gave me exactly what I was looking for. Read on for my solution to the problem.
I want a splash screen to fade in from 0% opacity to 100% opacity while things boot up, with a minimum display time of 2000ms (to allow the full fade in effect to show). Once everything is ready, I want the splash screen to display for a further 500ms while the main screen displays behind the splash screen. Then I want the splash screen to go away, leaving the main screen running.
Note that I use the MVP pattern for winforms. If you don't use MVP, you will need to simplify the below example a little.
Long story short, you need to create an AppContext class that inherits from ApplicationContext. I have put this in my Program.cs as below:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.SetHighDpiMode(HighDpiMode.SystemAware);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new AppContext());
}
}
public class AppContext : ApplicationContext
{
private IMainPresenter _mainPresenter;
private bool _ready;
public AppContext()
{
_ready = false;
using (ISplashPresenter splashPresenter = new SplashPresenter(new SplashView()))
{
Stopwatch sw = Stopwatch.StartNew();
_mainPresenter = new MainPresenter(new MainView());
_mainPresenter.Closed += MainPresenter_Closed;
new Thread(() =>
{
// !!! Do work here !!!
if (sw.ElapsedMilliseconds < 2000)
Thread.Sleep(2000 - (int)sw.ElapsedMilliseconds);
_ready = true;
})
.Start();
while (!_ready)
{
Application.DoEvents();
Thread.Sleep(1);
}
_mainPresenter.Show();
_ready = false;
new Thread(() =>
{
Thread.Sleep(500);
_ready = true;
})
.Start();
while (!_ready)
{
Application.DoEvents();
Thread.Sleep(1);
}
}
}
private void MainPresenter_Closed(object sender, EventArgs e)
{
ExitThread();
}
}
There are several implementation specific details that I haven't gone into here, such as ISplashPresenter implementing IDisposable and exactly how the fade in is managed; if enough people request it I will edit this answer to include a complete example.
First you should create a form with or without Border (border-less is preferred for these things)
public class SplashForm : Form
{
Form _Parent;
BackgroundWorker worker;
public SplashForm(Form parent)
{
InitializeComponent();
BackgroundWorker worker = new BackgroundWorker();
this.worker.DoWork += new System.ComponentModel.DoWorkEventHandler(this.worker _DoWork);
backgroundWorker1.RunWorkerAsync();
_Parent = parent;
}
private void worker _DoWork(object sender, DoWorkEventArgs e)
{
Thread.sleep(500);
this.hide();
_Parent.show();
}
}
At Main you should use that
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new SplashForm());
}
}
Maybe a bit late to answer but i would like to share my way.
I found an easy way with threads in the main program for a winform application.
Lets say you have your form "splashscreen" with an animation, and your "main" which has all your application code.
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Thread mythread;
mythread = new Thread(new ThreadStart(ThreadLoop));
mythread.Start();
Application.Run(new MainForm(mythread));
}
public static void ThreadLoop()
{
Application.Run(new SplashScreenForm());
}
In your main form in the constructor:
public MainForm(Thread splashscreenthread)
{
InitializeComponent();
//add your constructor code
splashscreenthread.Abort();
}
This way the splashscreen will last just the time for your main form to load.
Your splashcreen form should have his own way to animate/display information.
In my project my splashscreen start a new thread, and every x milliseconds it changes his main picture to another which is a slightly different gear, giving the illusion of a rotation.
example of my splashscreen:
int status = 0;
private bool IsRunning = false;
public Form1()
{
InitializeComponent();
StartAnimation();
}
public void StartAnimation()
{
backgroundWorker1.WorkerReportsProgress = false;
backgroundWorker1.WorkerSupportsCancellation = true;
IsRunning = true;
backgroundWorker1.RunWorkerAsync();
}
public void StopAnimation()
{
backgroundWorker1.CancelAsync();
}
delegate void UpdatingThreadAnimation();
public void UpdateAnimationFromThread()
{
try
{
if (label1.InvokeRequired == false)
{
UpdateAnimation();
}
else
{
UpdatingThreadAnimation d = new UpdatingThreadAnimation(UpdateAnimationFromThread);
this.Invoke(d, new object[] { });
}
}
catch(Exception e)
{
}
}
private void UpdateAnimation()
{
if(status ==0)
{
// mypicture.image = image1
}else if(status ==1)
{
// mypicture.image = image2
}
//doing as much as needed
status++;
if(status>1) //change here if you have more image, the idea is to set a cycle of images
{
status = 0;
}
this.Refresh();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
while (IsRunning == true)
{
System.Threading.Thread.Sleep(100);
UpdateAnimationFromThread();
}
}
Hope this will help some people.
Sorry if i have made some mistakes. English is not my first language.
Here is the easiest way of creating a splash screen:
First of all, add the following line of code before the namespace in Form1.cs code:
using System.Threading;
Now, follow the following steps:
Add a new form in you application
Name this new form as FormSplashScreen
In the BackgroundImage property, choose an image from one of your folders
Add a progressBar
In the Dock property, set it as Bottom
In MarksAnimationSpeed property, set as 50
In your main form, named as Form1.cs by default, create the following method:
private void StartSplashScreen()
{
Application.Run(new Forms.FormSplashScreen());
}
In the constructor method of Form1.cs, add the following code:
public Form1()
{
Thread t = new Thread(new ThreadStart(StartSplashScreen));
t.Start();
Thread.Sleep(5000);
InitializeComponent();//This code is automatically generated by Visual Studio
t.Abort();
}
Now, just run the application, it is going to work perfectly.
Here's my 2023 take on a 2011 question.
Over time, I've done this many times in many ways. The approach that currently use:
Force the main form Handle creation so that the message that creates the splash can be posted into the main form's message queue using BeginInvoke. This allows the main form ctor to return. Ordinarily the handle (the native hWnd) doesn't come into existence until it's shown. Therefore, it needs to be coerced while it's still hidden.
Override the SetVisibleCore() preventing the main window from becoming visible until the Splash has finished processing.
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
Debug.Assert(!IsHandleCreated, "Expecting handle is not yet created.");
// Ordinarily we don't get the handle until
// window is shown. But we want it now.
_ = Handle;
Debug.Assert(IsHandleCreated, "Expecting handle exists.");
// Call BeginInvoke on the new handle so as not to block the CTor.
BeginInvoke(new Action(()=> execSplashFlow()));
}
protected override void SetVisibleCore(bool value) =>
base.SetVisibleCore(value && _initialized);
bool _initialized = false;
private void execSplashFlow()
{
using (var splash = new SplashForm())
{
splash.ShowDialog();
}
_initialized= true;
WindowState = FormWindowState.Maximized;
Show();
}
}
Splash Example
The async initialization can be performed in the Splash class itself or it can fire events causing the main app to do things. Either way, when it closes itself the main form will set the _initialized bool to true and it is now capable of becoming visible.
public partial class SplashForm : Form
{
public SplashForm()
{
InitializeComponent();
StartPosition = FormStartPosition.CenterScreen;
FormBorderStyle = FormBorderStyle.None;
}
protected async override void OnVisibleChanged(EventArgs e)
{
base.OnVisibleChanged(e);
if (Visible)
{
labelProgress.Text = "Updating installation...";
progressBar.Value = 5;
await Task.Delay(1000);
progressBar.Value = 25;
// SIMULATED background task like making an API call or loading a
// database (long-running task that doesn't require the UI thread).
labelProgress.Text = "Loading avatars...";
await Task.Delay(1000);
labelProgress.Text = "Fetching game history...";
progressBar.Value = 50;
await Task.Delay(1000);
labelProgress.Text = "Initializing scenario...";
progressBar.Value = 75;
await Task.Delay(1000);
labelProgress.Text = "Success!";
progressBar.Value = 100;
await Task.Delay(1000);
DialogResult= DialogResult.OK;
}
}
}
Try this code
public partial class ssplashscreen : Form
{
public ssplashscreen()
{
InitializeComponent();
}
private void timer1_Tick(object sender, EventArgs e)
{
progressBar1.Increment(1);
if (progressBar1.Value == 100)
{
timer1.Stop();
this.Hide();
Form frm = new login();
frm.Show();
}
}
}
Try This:
namespace SplashScreen
{
public partial class frmSplashScreen : Form
{
public frmSplashScreen()
{
InitializeComponent();
}
public int LeftTime { get; set; }
private void frmSplashScreen_Load(object sender, EventArgs e)
{
LeftTime = 20;
timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
if (LeftTime > 0)
{
LeftTime--;
}
else
{
timer1.Stop();
new frmHomeScreen().Show();
this.Hide();
}
}
}
}
How can I display the Wait/Busy Cursor (usually the hourglass) to the user to let them know the program is doing something?
You can use Cursor.Current.
// Set cursor as hourglass
Cursor.Current = Cursors.WaitCursor;
// Execute your time-intensive hashing code here...
// Set cursor as default arrow
Cursor.Current = Cursors.Default;
However, if the hashing operation is really lengthy (MSDN defines this as more than 2-7 seconds), you should probably use a visual feedback indicator other than the cursor to notify the user of the progress. For a more in-depth set of guidelines, see this article.
Edit:
As #Am pointed out, you may need to call Application.DoEvents(); after Cursor.Current = Cursors.WaitCursor; to ensure that the hourglass is actually displayed.
Actually,
Cursor.Current = Cursors.WaitCursor;
temporarily sets the Wait cursor, but doesn’t ensure that the Wait cursor shows until the end of your operation. Other programs or controls within your program can easily reset the cursor back to the default arrow as in fact happens when you move mouse while operation is still running.
A much better way to show the Wait cursor is to set the UseWaitCursor property in a form to true:
form.UseWaitCursor = true;
This will display wait cursor for all controls on the form until you set this property to false.
If you want wait cursor to be shown on Application level you should use:
Application.UseWaitCursor = true;
Building on the previous, my preferred approach (since this is a frequently performed action) is to wrap the wait cursor code in an IDisposable helper class so it can be used with using() (one line of code), take optional parameters, run the code within, then clean up (restore cursor) afterwards.
public class CursorWait : IDisposable
{
public CursorWait(bool appStarting = false, bool applicationCursor = false)
{
// Wait
Cursor.Current = appStarting ? Cursors.AppStarting : Cursors.WaitCursor;
if (applicationCursor) Application.UseWaitCursor = true;
}
public void Dispose()
{
// Reset
Cursor.Current = Cursors.Default;
Application.UseWaitCursor = false;
}
}
Usage:
using (new CursorWait())
{
// Perform some code that shows cursor
}
It is easier to use UseWaitCursor at the Form or Window level.
A typical use case can look like below:
private void button1_Click(object sender, EventArgs e)
{
try
{
this.Enabled = false;//optional, better target a panel or specific controls
this.UseWaitCursor = true;//from the Form/Window instance
Application.DoEvents();//messages pumped to update controls
//execute a lengthy blocking operation here,
//bla bla ....
}
finally
{
this.Enabled = true;//optional
this.UseWaitCursor = false;
}
}
For a better UI experience you should use Asynchrony from a different thread.
My approach would be to make all the calculations in a background worker.
Then change the cursor like this:
this.Cursor = Cursors.Wait;
And in the thread's finish event restore the cursor:
this.Cursor = Cursors.Default;
Note, this can also be done for specific controls, so the cursor will be the hourglass only when the mouse is above them.
For Windows Forms applications an optional disabling of a UI-Control can be very useful. So my suggestion looks like this:
public class AppWaitCursor : IDisposable
{
private readonly Control _eventControl;
public AppWaitCursor(object eventSender = null)
{
_eventControl = eventSender as Control;
if (_eventControl != null)
_eventControl.Enabled = false;
Application.UseWaitCursor = true;
Application.DoEvents();
}
public void Dispose()
{
if (_eventControl != null)
_eventControl.Enabled = true;
Cursor.Current = Cursors.Default;
Application.UseWaitCursor = false;
}
}
Usage:
private void UiControl_Click(object sender, EventArgs e)
{
using (new AppWaitCursor(sender))
{
LongRunningCall();
}
}
Okey,Other people's view are very clear, but I would like to do some added, as follow:
Cursor tempCursor = Cursor.Current;
Cursor.Current = Cursors.WaitCursor;
//do Time-consuming Operations
Cursor.Current = tempCursor;
OK so I created a static async method. That disabled the control that launches the action and changes the application cursor. It runs the action as a task and waits for to finish. Control returns to the caller while it waits. So the application remains responsive, even while the busy icon spins.
async public static void LengthyOperation(Control control, Action action)
{
try
{
control.Enabled = false;
Application.UseWaitCursor = true;
Task doWork = new Task(() => action(), TaskCreationOptions.LongRunning);
Log.Info("Task Start");
doWork.Start();
Log.Info("Before Await");
await doWork;
Log.Info("After await");
}
finally
{
Log.Info("Finally");
Application.UseWaitCursor = false;
control.Enabled = true;
}
Here's the code form the main form
private void btnSleep_Click(object sender, EventArgs e)
{
var control = sender as Control;
if (control != null)
{
Log.Info("Launching lengthy operation...");
CursorWait.LengthyOperation(control, () => DummyAction());
Log.Info("...Lengthy operation launched.");
}
}
private void DummyAction()
{
try
{
var _log = NLog.LogManager.GetLogger("TmpLogger");
_log.Info("Action - Sleep");
TimeSpan sleep = new TimeSpan(0, 0, 16);
Thread.Sleep(sleep);
_log.Info("Action - Wakeup");
}
finally
{
}
}
I had to use a separate logger for the dummy action (I am using Nlog) and my main logger is writing to the UI (a rich text box). I wasn't able to get the busy cursor show only when over a particular container on the form (but I didn't try very hard.) All controls have a UseWaitCursor property, but it doesn't seem have any effect on the controls I tried (maybe because they weren't on top?)
Here's the main log, which shows things happening in the order we expect:
16:51:33.1064 Launching lengthy operation...
16:51:33.1215 Task Start
16:51:33.1215 Before Await
16:51:33.1215 ...Lengthy operation launched.
16:51:49.1276 After await
16:51:49.1537 Finally
With the class below you can make the suggestion of Donut "exception safe".
using (new CursorHandler())
{
// Execute your time-intensive hashing code here...
}
the class CursorHandler
public class CursorHandler
: IDisposable
{
public CursorHandler(Cursor cursor = null)
{
_saved = Cursor.Current;
Cursor.Current = cursor ?? Cursors.WaitCursor;
}
public void Dispose()
{
if (_saved != null)
{
Cursor.Current = _saved;
_saved = null;
}
}
private Cursor _saved;
}
Use this with WPF:
Cursor = Cursors.Wait;
// Your Heavy work here
Cursor = Cursors.Arrow;
You can use:
Mouse.OverrideCursor = Cursors.Wait;
&&
Mouse.OverrideCursor = Cursors.Arrow;