I am having a MDI form, now clicking on the menu in MDI form, I am opening other forms in PnlView (Panel), this acts as container for forms.
What I am thinking is, when the application loads, it opens a default form.
At this point I want to open all forms, but as opening all forms at a time will hamper the performance, other forms opening should run in different thread. Then if all forms are open then user can switch between forms quickly.
private bool IsFormAlreadyOpen(ControlItem _item)
{
bool reutrnValue = false;
foreach (Control ctrl in PnlView.Controls)
{
if (ctrl.Name.ToLower() == _item.Control.Name.ToLower())
{
reutrnValue = true;
break;
}
}
return reutrnValue;
}
This is the function which checks if form is already opened or not. So this will get all the forms open and will just bring that form to front.
Can anyone helps me with opening form in thread so that it will not impact the performance.
I hope this makes sense.
---------------------------------------------------------------------
private void MdiForm1_Load(object sender, EventArgs e)
{
OpenFirstForm(); //This ospens a default form, form name frmDefault
bw.WorkerReportsProgress = true;
bw.WorkerSupportsCancellation = true;
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
bw.RunWorkerAsync();
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
//this.tbProgress.Text = (e.ProgressPercentage.ToString() + "%");
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
for (int i = 1; (i <= 2); i++)
{
if ((worker.CancellationPending == true))
{
e.Cancel = true;
break;
}
else
{
// Perform a time consuming operation and report progress.
//System.Threading.Thread.Sleep(500);
OpenForms(form1);
OpenForms(form2);
worker.ReportProgress((i * 10));
}
}
}
It throws an exception,
Cross-thread operation not valid: Control '' accessed from a thread other than the thread it was created on
Getting below exception,
No Overload 'OpenForm' matches delegate MethodInvoker
this.Invoke(new MethodInvoker(OpenForm),new object[] { Keys.F12, Keys.Alt });
private void OpenForm(Keys keyPressed, Keys modifier)
{
---------------------------
}
The problem is that you are trying to access a control instantiated in one thread from another thread. Use the following code snippet to solve your issue at hand:
// Paste this snippet in the beginning of your method
if (InvokeRequired)
{
this.Invoke(new MethodInvoker(/*Enter the name of your method here*/));
return;
}
// Method code goes here ......
/*
Example:
private void SomeMethod(object sender, EventArgs e) {
if (InvokeRequired)
{
this.Invoke(new MethodInvoker(SomeMethod)); // Name of current method is 'SomeMethod'
return;
}
// Code continues here
int x,y,z;
// Do something .....
}
*/
Hope this helps.
Related
Good morning, I'm trying to write an application that use in his interface a progressbar (in C#, WPF). I have read about the need of perform the UI task in a different thread, using Backgroundworker. I trying to make it work using a lot of information, but nothing happens (the program work fine, but the progressbar only shown at the end of the "hard-work tasks").
I'm civil engineer (not a software one), so I ask if anyone can help me with that.
namespace SAP2000___Quake_Definitions
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private readonly BackgroundWorker bgWoker = new BackgroundWorker();
public MainWindow()
{
InitializeComponent();
this.bgWoker.WorkerReportsProgress = true;
this.bgWoker.WorkerSupportsCancellation = true;
this.bgWoker.DoWork += bgWorker_DoWork;
this.bgWoker.ProgressChanged += bgWorker_ProgressChanged;
this.bgWoker.RunWorkerCompleted += bgWorker_RunWorkerCompleted;
}
private void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.progBar.Value = e.ProgressPercentage;
}
private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker bgWorker = (BackgroundWorker)sender;
Dispatcher.Invoke(new Action(() => DoTheHardWork()));
}
private void processButton_Click(object sender, RoutedEventArgs e)
{
this.bgWoker.RunWorkerAsync();
}
private void DoTheHardWork()
{
switch (this.chckBox2.IsChecked.GetValueOrDefault())
{
case true:
this.bgWoker.ReportProgress(0);
//more hardwork with inputs from WPF
case false:
this.bgWoker.ReportProgress(0);
//more hardwork with inputs from WPF
}
}
}
}
That is not how you should be using a BackgroundWorker. I wrote some example code a few years back. It should get you on the right track:
#region Primenumbers
private void btnPrimStart_Click(object sender, EventArgs e)
{
if (!bgwPrim.IsBusy)
{
//Prepare ProgressBar and Textbox
int temp = (int)nudPrim.Value;
pgbPrim.Maximum = temp;
tbPrim.Text = "";
//Start processing
bgwPrim.RunWorkerAsync(temp);
}
}
private void btnPrimCancel_Click(object sender, EventArgs e)
{
if (bgwPrim.IsBusy)
{
bgwPrim.CancelAsync();
}
}
private void bgwPrim_DoWork(object sender, DoWorkEventArgs e)
{
int highestToCheck = (int)e.Argument;
//Get a reference to the BackgroundWorker running this code
//for Progress Updates and Cancelation checking
BackgroundWorker thisWorker = (BackgroundWorker)sender;
//Create the list that stores the results and is returned by DoWork
List<int> Primes = new List<int>();
//Check all uneven numbers between 1 and whatever the user choose as upper limit
for(int PrimeCandidate=1; PrimeCandidate < highestToCheck; PrimeCandidate+=2)
{
//Report progress
thisWorker.ReportProgress(PrimeCandidate);
bool isNoPrime = false;
//Check if the Cancelation was requested during the last loop
if (thisWorker.CancellationPending)
{
//Tell the Backgroundworker you are canceling and exit the for-loop
e.Cancel = true;
break;
}
//Determin if this is a Prime Number
for (int j = 3; j < PrimeCandidate && !isNoPrime; j += 2)
{
if (PrimeCandidate % j == 0)
isNoPrime = true;
}
if (!isNoPrime)
Primes.Add(PrimeCandidate);
}
//Tell the progress bar you are finished
thisWorker.ReportProgress(highestToCheck);
//Save Return Value
e.Result = Primes.ToArray();
}
private void bgwPrim_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
pgbPrim.Value = e.ProgressPercentage;
}
private void bgwPrim_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
pgbPrim.Value = pgbPrim.Maximum;
this.Refresh();
if (!e.Cancelled && e.Error == null)
{
//Show the Result
int[] Primes = (int[])e.Result;
StringBuilder sbOutput = new StringBuilder();
foreach (int Prim in Primes)
{
sbOutput.Append(Prim.ToString() + Environment.NewLine);
}
tbPrim.Text = sbOutput.ToString();
}
else
{
tbPrim.Text = "Operation canceled by user or Exception";
}
}
#endregion
You have to limit all UI writing work to the Progress Report and Run wokrer compelte Events. Those will be raised in the thread that created the BGW (wich should be the UI thread) automagically.
Note that you can only report progress between distinct steps. I had the advantage that I had to write the loop anyway. But if you have existing code (like most download or disk code), you can usually only report between files.
my mistakes were three:
Trying to use "Dispatcher.Invoke(new Action(() => DoTheHardWork()));" to solve an exception related to my thread (exception caused by point #3).
Avoiding the instantiation: BackgroundWorker bgWorker = (BackgroundWorker)sender (thank you #Christopher).
Writing a code that manipulate a UI-Component inside the DoWork event handle of my Backgroundworker. MSDN says: You must be careful not to manipulate any user-interface objects in your DoWork event handler. Instead, communicate to the user interface through the ProgressChanged and RunWorkerCompleted events. Trying this, the exception occur.
Solving the point #2 and #3, the UI is perfectly responsive respect to the "hardwork" function (runned in background).
I'm using WPF and I have main thread which is GUI (wizard).
When user click Finish on wizard it open second thread which display user progress bar used in background worker.
In Main thread I doing:
MessageWithProgressBar progress = new MessageWithProgressBar();
progress.Show();
createFilesInA();
createFilesInB();
createFilesInC();
createFilesInD();
createFilesInE();
createFilesInF();
createFilesInG();
createFilesInH();
createFilesInI();
createFilesInJ();
createFilesInK();
In each createFiles method I increment by 1 the static variable called currentStep which I used it in background worker as detailed below.
In background worker I doing:
public partial class MessageWithProgressBar : Window
{
private BackgroundWorker backgroundWorker = new BackgroundWorker();
public MessageWithProgressBar()
{
InitializeComponent();
backgroundWorker.WorkerReportsProgress = true;
backgroundWorker.ProgressChanged += ProgressChanged;
backgroundWorker.DoWork += DoWork;
backgroundWorker.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted;
}
private void DoWork(object sender, DoWorkEventArgs e)
{
Thread.Sleep(100);
int i = GeneralProperties.General.currentStep;
if (i > GeneralProperties.General.thresholdStep)
{
progress.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
new DispatcherOperationCallback(delegate
{
progress.Value = 100;
title.Content = progress.Value.ToString();
return null;
}), null);
return;
}
else
{
progress.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
new DispatcherOperationCallback(delegate
{
progress.Value = (int)Math.Floor((decimal)(8 * i));
progressLabel.Text = progress.Value.ToString();
return null;
}), null);
}
}
private void ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progress.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
new DispatcherOperationCallback(delegate
{
progress.Value = e.ProgressPercentage;
return null;
}), null);
}
private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
progress.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
new DispatcherOperationCallback(delegate
{
progress.Value = 100;
title.Content = progress.Value.ToString();
return null;
}), null);
WindowMsgGenDB msg = new WindowMsgGenDB();
msg.Show();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
if (backgroundWorker.IsBusy == false)
{
backgroundWorker.RunWorkerAsync();
}
}
}
The main thread updated variable called currentStep and the second thread used it to report on the main thread progress.
The operations of the main thread takes a few seconds (not more 15 seconds)
I have two issues:
I see on progress bar only when currentStep=2 (then the progress is 16) and then the progress is 100, and I don't see every step
At the beginning, the progress bar is freeze and it seems like it stuck.
(maybe it connects to the call progress.Show() from the main thread?)
Thanks!
As far as I understand your code your background worker is not doing anything, really. It updates the progress once and that's it.
Also: using global static variables to communicate between a form and a background worker - ouch...
Also, you're using it wrong in my opinion. The work (CreateFilesInA ... CreateFilesInK) should be done by the background worker - that's what it is for. As the main thread will be blocked the way you implemented it, you will not see any updates otherwise.
The usual way to implement something like this is:
Create progress window and disable UI
Start background worker that does stuff in DoWork. In DoWork, after every call to a CreateFilesInXYZ method, call ReportProgress to the the UI be updated.
Update stuff in progress window whenever ProgressChanged event is fired
Hide progress window and enable your application's UI when background worker is done
The way you're doing it it's in no way asynchronous. So, actually, your code should look something like this:
public partial class MainWindow : Window
{
private BackgroundWorker backgroundWorker = new BackgroundWorker();
private MessageWithProgressBar progressWindow;
public MainWindow()
{
InitializeComponent();
backgroundWorker.WorkerReportsProgress = true;
backgroundWorker.ProgressChanged += ProgressChanged;
backgroundWorker.DoWork += DoWork;
backgroundWorker.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted;
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
progressWindow = new MessageWithProgressBar();
progressWindow.Owner = this;
progressWindow.Show();
backgroundWorker.RunWorkerAsync();
}
private void DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = (BackgroundWorker)sender;
int numSteps = 11;
int currentStep = 0;
int progress = 0;
CreateFilesInA();
currentStep += 1;
progress = (int)((float)currentStep / (float)numSteps * 100.0);
worker.ReportProgress(progress);
CreateFilesInB();
currentStep += 1;
progress = (int)((float)currentStep / (float)numSteps * 100.0);
worker.ReportProgress(progress);
// All other steps here
...
}
private void ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressWindow.progress.Value = e.ProgressPercentage;
}
private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
progressWindow.Close();
WindowMsgGenDB msg = new WindowMsgGenDB();
msg.Show();
}
}
Please note that the above code goes into your main window! The MessageWithProgressWindow does not contain any code. Maybe the Window_Loaded event handler is not the right place to start the background worker, but you get the picture.
I am making a search utility and using a BackgroundWorker to search. I want that as soon as the first result is found , a new window should open up with a ListBox with the first element displayed. Now, I want that as soon as subsequent results are found, the ListBox should be updated with those results.
The method thought by me was to report the progress as soon as results are found and pass "New" and "Update" as userState to the method.
Based on the userState, I can decide whether to create a new Form or update and existing one.
Here is the code :-
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (e.UserState.ToString() == "New")
{
Form ResultForm = new Form();
ResultForm.Name = "ResultForm" + i.ToString();
LastFormName = ResultForm.Name;
ListBox ResultListBox = new ListBox();
ResultListBox.DataSource = SearchList;
ResultListBox.Name = "ResultListBox" + i.ToString();
LastListName = ResultListBox.Name ;
ResultForm.Container.Add(ResultListBox);
ResultListBox.Show();
ResultForm.Show();
i++;
}
else
{
;
}
}
I have stored the names of the Last open Form and it's ListBox in the variables LastFormName and 'LastListName'.
I am unable to understand what to put in the else condition, so as to update the ListBox.
What I would do is expose some properties on the popup form so that you can tell if it is open and have access to the list box.
public partial class Popup : Form
{
public bool isOpen;
public ListBox PopupListBox;
public Popup()
{
InitializeComponent();
}
void Popup_FormClosing(object sender, FormClosingEventArgs e)
{
isOpen = false;
}
private void Popup_Load(object sender, EventArgs e)
{
this.FormClosing += Popup_FormClosing;
PopupListBox = popupListBox;
}
}
Then on the calling form I would subscribe to the ProcessedChanged Event and update the listbox with the data you are passing through the ProcessedChangedEventArgs. Here is the code for the calling form
public partial class Form1 : Form
{
Popup popupForm = new Popup();
BackgroundWorker backgroundWorker = new BackgroundWorker();
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
backgroundWorker.WorkerSupportsCancellation = true;
backgroundWorker.WorkerReportsProgress = true;
backgroundWorker.DoWork += backgroundWorkerDoWork;
backgroundWorker.ProgressChanged += backgroundWorkerProgressChanged;
backgroundWorker.RunWorkerCompleted += backgroundWorkerRunWorkerCompleted;
}
void backgroundWorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if ((e.Cancelled == true))
{
//What do you want to do if Cancelled?
}
else if (!(e.Error == null))
{
//What do you want to do if there is an error?
}
else
{
//What do you want to do when it is done?
}
}
void backgroundWorkerProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (!popupForm.isOpen || popupForm == null)
{
popupForm = new Popup();
popupForm.Show();
popupForm.isOpen = true;
}
else
{
popupForm.Activate();
popupForm.WindowState = FormWindowState.Normal;
}
popupForm.PopupListBox.Items.Add(e.ProgressPercentage.ToString() + "%");
}
void backgroundWorkerDoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
for (int i = 1; (i <= 10); i++)
{
if ((worker.CancellationPending == true))
{
e.Cancel = true;
break;
}
else
{
// Perform a time consuming operation and report progress.
System.Threading.Thread.Sleep(500);
worker.ReportProgress((i * 10));
}
}
}
private void buttonStart_Click(object sender, EventArgs e)
{
if (backgroundWorker.IsBusy != true)
{
backgroundWorker.RunWorkerAsync();
}
}
private void buttonCancel_Click(object sender, EventArgs e)
{
if (backgroundWorker.WorkerSupportsCancellation == true)
{
backgroundWorker.CancelAsync();
}
}
}
You shouldn't be doing work in the ProgressChanged event handler
You won't have access to the results as it is only passed an int for progress and user state
This is on the UI thread. The entire point is to do your processing on a background thread
The name DoWork event handler is clear that this is where you should do your processing.
In answer to your question. Since you create the ListBox in your event handler it goes out of scope outside the if statement. You need to create this in a more global scope. Then to add to it ResultListBox.Items.Add("ResultListBox" + i.ToString());
I have some process heavy tasks that run in my WinForms app. The problem is, while its running, it freeze the UI (UI main thread).
I haven't worked that much with threads and delegates in C# yet, and that's why I hope someone could help me to, how to handle those process heavy tasks, without freezing the UI, so the user don't think the app is crashing while waiting?
Eg. I have a call through my FrontController, that takes time:
_controller.testExportExcel(wrapper, saveDialog.FileName);
Since it's creating an Excel file. I won't the app to be responding on the UI while its working.
Another example of a process heavy task could be this:
private void dataGridView_liste_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
if (e.ListChangedType != ListChangedType.ItemDeleted)
{
foreach (DataGridViewRow r in dataGridView_liste.Rows)
{
DataGridViewCellStyle red = dataGridView_liste.DefaultCellStyle.Clone();
red.BackColor = Color.LightGreen;
if (r.Cells["News"].Value != null && (bool)r.Cells["News"].Value == true)
r.DefaultCellStyle = red;
}
}
}
Where the foreach loop takes time, and freeze the UI. An async thread running the process and automatically closing when its done, could be useful I think. But how does it work??
How about using a Task (if targetting .net 4)? This is considered as a replacement of the BackgroundWorker class since it supports nesting (parent/child tasks), task continuations, etc.
E.g.
private void dataGridView_liste_DataBindingComplete(object sender,
DataGridViewBindingCompleteEventArgs e)
{
Task t = Task.Factory.StartNew(() =>
{
// do your processing here - remember to call Invoke or BeginInvoke if
// calling a UI object.
});
t.ContinueWith((Success) =>
{
// callback when task is complete.
}, TaskContinuationOptions.NotOnFaulted);
t.ContinueWith((Fail) =>
{
//log the exception i.e.: Fail.Exception.InnerException);
}, TaskContinuationOptions.OnlyOnFaulted);
}
I answered a very similar question here
It boils down to using BackgroundWorker.
msdn provides an example:
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
namespace SL_BackgroundWorker_CS
{
public partial class Page : UserControl
{
private BackgroundWorker bw = new BackgroundWorker();
public Page()
{
InitializeComponent();
bw.WorkerReportsProgress = true;
bw.WorkerSupportsCancellation = true;
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
}
private void buttonStart_Click(object sender, RoutedEventArgs e)
{
if (bw.IsBusy != true)
{
bw.RunWorkerAsync();
}
}
private void buttonCancel_Click(object sender, RoutedEventArgs e)
{
if (bw.WorkerSupportsCancellation == true)
{
bw.CancelAsync();
}
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
for (int i = 1; (i <= 10); i++)
{
if ((worker.CancellationPending == true))
{
e.Cancel = true;
break;
}
else
{
// Perform a time consuming operation and report progress.
System.Threading.Thread.Sleep(500);
worker.ReportProgress((i * 10));
}
}
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if ((e.Cancelled == true))
{
this.tbProgress.Text = "Canceled!";
}
else if (!(e.Error == null))
{
this.tbProgress.Text = ("Error: " + e.Error.Message);
}
else
{
this.tbProgress.Text = "Done!";
}
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.tbProgress.Text = (e.ProgressPercentage.ToString() + "%");
}
}
}
Everything that runs in the DoWork event handler is asynchronous.
Everything that runs in ProgessChanged/RunWorkCompleted's event handlers is on the UI thread.
For your first example, a call to _controller.testExportExcel(), a BackgroundWorker or Task Parallel Library call (i.e. Task.Factory.StartNew(...)) would be appropriate to satify your requirement of keeping the UI responsive. Plenty of examples floating around, including the other answers here.
For your second example, you will find you can't put this on a background thread since it appears to be code that manipulates the UI. Specifically, if the implementation of your BackgroundWorker's DoWork event handler, or the delegate you pass to Task.Factory.StartNew(), or the method for a plain old thread touch the UI, you are highly likely (/certain?) to get an exception stating "Cross-thread operation not valid".
The reason for this is covered in this question. But I'm more surprised actually this is slow enough that you want to make it asynchronous. There might be some simple ways to make this code more responsive - Control.SuspendLayout() and .ResumeLayout() springs to mind.
I do some checks on form load, but it is locking the form for a period (some thousandths of seconds). For this reason, I want to display a message such as "loading application..", but I have no idea how I do this. I hope this clear! Any help is very appreciated. Thanks in advance.
Ideally what you want to do is to perform your checks on a background thread, so that the UI thread isn't blocked. Have a look at the BackgroundWorker class.
You should hook your checks to the DoWork event of the background worker, and call the BackgroundWorker's RunWorkerAsync() method from the Form_Load event to kick off the background work.
Something like this (note, this is untested):
BackgroundWorker bw = new BackgroundWorker();
public void Form_Load(Object sender, EventArgs e) {
// Show the loading label before we start working...
loadingLabel.Show();
bw.DoWork += (s, e) => {
// Do your checks here
}
bw.RunWorkerCompleted += (s, e) => {
// Hide the loading label when we are done...
this.Invoke(new Action(() => { loadingLabel.Visible = false; }));
};
bw.RunWorkerAsync();
}
You can create another thread to display the loading message.
First you need a bool.
bool loading = true;
Create a thread like:
Thread myThread = new Thread(new ThreadStart(Loading));
myThread .Start();
Then have a method:
private void Loading()
{
while(loading)
{
//Display loading message here.
}
}
When you are done loading whatever just set loading to false and the tread will terminate.
Have a look at BackgroundWorker component. You dont need any threading knowledge at all.
This can be accomplished easily by displaying a separate form executed on another thread. In this form (call it frmSplash) you can put an animated gif or static text. The code you will need is as follows in your main form:
Declare some variables after the class.
public partial class frmMain : Form
{
public Thread th1;
static frmSplash splash;
const int kSplashUpdateInterval_ms = 1;
// Rest of code omitted
Then add the following method to your main form. This starts the splash screen:
static public void StartSplash()
{
// Instance a splash form given the image names
splash = new frmSplash(kSplashUpdateInterval_ms);
// Run the form
Application.Run(splash);
}
Next, you need a method to close the splash screen:
private void CloseSplash()
{
if (splash == null)
return;
// Shut down the splash screen
splash.Invoke(new EventHandler(splash.KillMe));
splash.Dispose();
splash = null;
}
Then, in your main Form Load, do this:
private void frmMain_Load(object sender, EventArgs e)
{
try
{
Thread splashThread = new Thread(new ThreadStart(StartSplash));
splashThread.Start();
// Set the main form invisible so that only the splash form shows
this.Visible = false;
// Perform all long running work here. Loading of grids, checks etc.
BindSalesPerson();
BindCustomer();
BindBrand();
// Set the main form visible again
this.Visible = true;
}
catch (Exception ex)
{
// Do some exception handling here
}
finally
{
// After all is done, close your splash. Put it here, so that if your code throws an exception, the finally will close the splash form
CloseSplash();
}
}
Then, if the main form is closed, make sure your splash screen is closed also:
protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
{
// Make sure the splash screen is closed
CloseSplash();
base.OnClosing(e);
}
The code for the Splash form (In frmSplash.cs) is as follows:
public partial class frmSplash : Form
{
System.Threading.Timer splashTimer = null;
int curAnimCell = 0;
int numUpdates = 0;
int timerInterval_ms = 0;
public frmSplash(int timerInterval)
{
timerInterval_ms = timerInterval;
InitializeComponent();
}
private void frmSplash_Load(object sender, EventArgs e)
{
this.Text = "";
this.MaximizeBox = false;
this.MinimizeBox = false;
this.ControlBox = false;
this.FormBorderStyle = FormBorderStyle.None;
this.Menu = null;
}
public int GetUpMilliseconds()
{
return numUpdates * timerInterval_ms;
}
public void KillMe(object o, EventArgs e)
{
//splashTimer.Dispose();
this.Close();
}
}
I hope this helps you. It might not be the best code ever written, but it worked for me.
You need to create one form that is frmloading here.. you need to create object of that form and called using threading concept..and in FrmLoading put one Picturebox and set .gif image in it.
FrmLoading f2 = new FrmLoading();
using (new PleaseWait(this.Location, () =>MethodWithParameter())) { f2.Show(this); }
f2.Close();
As shown above code you need to create PleaseWait class.
PleaseWait.cs
public class PleaseWait : IDisposable
{
private FrmLoading mSplash;
private Point mLocation;
public PleaseWait(Point location, System.Action methodWithParameters)
{
mLocation = location;
Thread t = new Thread(new ThreadStart(workerThread));
t.IsBackground = true;
t.SetApartmentState(ApartmentState.STA);
t.Start();
methodWithParameters();
}
public void Dispose()
{
mSplash.Invoke(new MethodInvoker(stopThread));
}
private void stopThread()
{
mSplash.Close();
}
private void workerThread()
{
mSplash = new FrmLoading(); // Substitute this with your own
mSplash.StartPosition = FormStartPosition.CenterScreen;
//mSplash.Location = mLocation;
mSplash.TopMost = true;
Application.Run(mSplash);
}
}