progressbar and Data loading - c#

i have Windows Form in C# having Datagridview with large no. of records from database and some comboboxes,textbox and buttons.
so,i used another form having progressbar and backgroundworker so that data loading of mainform does not iritate enduser.
public partial class FirstForm : Form
{
MainForm mf;
public FirstForm()
{
InitializeComponent();
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
mf = new MainForm(); //inside constructor,code of data loading in gridview
mf.Update();
}
private void timer1_Tick(object sender, EventArgs e)
{
if (p1.Value < p1.Maximum) //p1 name for progressbar
p1.Value++;
else
{
timer1.Enabled = false;
this.Hide();
mf.Show();
}
}
}
but when main form is displayed,it is blank and after 2/3 seconds datagridview and other controls appear.
how to solve this..?
or suggest other ideas to solve this problem.

Remove your code in Firstform and write mine in
programs.cs
static void Main()
{
Application.EnableVisualStyles();
Application.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture;
Application.SetCompatibleTextRenderingDefault(false);
System.ComponentModel.BackgroundWorker bw = new System.ComponentModel.BackgroundWorker();
bw.DoWork += new System.ComponentModel.DoWorkEventHandler(bw_DoWork);
bw.WorkerSupportsCancellation = true;
MainForm = new MainForm(); // creating main form
bw.RunWorkerAsync();
frm.Inittiate(); // Add this method to first form to loading and initiating
bw.CancelAsync(); // ending splashing
Application.Run(frm);
}
static void bw_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
AFirstForm splashForm = new FirstForm();
splashForm.TopMost = true;
splashForm.Show();
while (!(sender as System.ComponentModel.BackgroundWorker).CancellationPending)
{
splashForm.Refresh();
}
splashForm.Close();
e.Result = splashForm;
}

Related

Invoke create handle from a backgroundworker

i'm working to populate a listview with a loop in a backgroundworker and the background worker was run initially from a 2nd active form. To picture it i've open a form1 then open another form (form2) that was use to run a form1.backgroundworker runasync.
Form1 with the backgroundworker - at the back
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker wk = new BackgroundWorker { WorkerReportsProgress = true };
listView1.View = View.Details;
DataTable dtdt = new DataTable();
dtdt = qr.history();
for (int i = 0; i < dtdt.Rows.Count; i++)
{
DataRow dr = dtdt.Rows[i];
ListViewItem listitem = new ListViewItem(dr["custnum"].ToString());
listitem.SubItems.Add(dr["custname"].ToString().Trim());
listitem.SubItems.Add(dr["ratecable"].ToString().Trim());
listitem.SubItems.Add(dr["rateinternet"].ToString().Trim());
listitem.SubItems.Add(dr["rateext"].ToString().Trim());
listitem.SubItems.Add(dr["status"].ToString().Trim());
listitem.SubItems.Add(dr["classname"].ToString().Trim());
listitem.SubItems.Add(dr["SVCstadd"].ToString().Trim());
listitem.SubItems.Add(dr["SVCctadd"].ToString().Trim());
listitem.SubItems.Add(dr["svctelno"].ToString().Trim());
listitem.SubItems.Add(dr["bilstadd"].ToString().Trim());
listitem.SubItems.Add(dr["bilctadd"].ToString().Trim());
listitem.SubItems.Add(dr["billtel"].ToString().Trim());
listitem.SubItems.Add(dr["billtel2"].ToString().Trim());
listitem.SubItems.Add(dr["fax"].ToString().Trim());
listitem.SubItems.Add(dr["zoneno"].ToString().Trim());
listitem.SubItems.Add(dr["zoneName"].ToString().Trim());
listitem.SubItems.Add(dr["bookno"].ToString().Trim());
listitem.SubItems.Add(dr["seqno"].ToString().Trim());
listitem.SubItems.Add(dr["Balance"].ToString().Trim());
listitem.SubItems.Add(dr["balance1"].ToString().Trim());
listitem.SubItems.Add(dr["balance2"].ToString().Trim());
listitem.SubItems.Add(dr["balance3"].ToString().Trim());
listitem.SubItems.Add(dr["billamnt"].ToString().Trim());
listitem.SubItems.Add(dr["maxdate"].ToString().Trim());
qr.lsi = listitem;
//error {"Invoke or BeginInvoke cannot be called on a control until the window handle has been created."}
this.BeginInvoke(new MethodInvoker(delegate { additemtoLV(listitem); }));
}
System.Threading.Thread.Sleep(100);
}
private delegate void additemtoLVdelegat(ListViewItem ls);
public void additemtoLV(ListViewItem ls)
{
if (IsHandleCreated)
{
BeginInvoke(new additemtoLVdelegat(additemtoLV), ls);
}
else
{
listView1.Items.Add(ls);
}
}
Form2 -use to call form1.backgroundworker - in front of form1 - note form1 is already open
private void Close_Click(object sender, EventArgs e)
{
form1 f1 = new form1 ();
f1.backgroundWorker1.RunWorkerAsync();
this.Close();
}
According to your code, form1 is not opened. You have to call Form.Show and wait for Form.Load.
form1 f1 = new form1 ();
f1.backgroundWorker1.RunWorkerAsync();
I suggest that you start background worker in Form1_Load
private void Form1_Load(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
And show Form1 to allow Form1_Load be fired.
private void Close_Click(object sender, EventArgs e)
{
form1 f1 = new form1();
f1.Show();
}

WinForm new form(waiting) is stuck when opens

I have wcf servise that Update db it is takes 10-15 sec,and i wont to run/show my form with loading/waitting statusbar while servise working, and when service is finished i need to close the watting form.
My problem is when i run ShowDialog(); it is get stuck on it , and don't go to my service.
What i doing wrong here?
My code
My function
public static void UpdateSNXRATES(object sender, EventArgs e)
{
WaitForm waitF = new WaitForm();
waitF.ShowDialog();//here it stuck
using (var Server = new ServiceReference.Service1Client())
{
Server.ClientCredentials.Windows.ClientCredential.Domain = strDomain;
Server.ClientCredentials.Windows.ClientCredential.UserName = strUser;
Server.ClientCredentials.Windows.ClientCredential.Password = strPassword;
success=Server.UpdateSNXRATES();
}
waitF.Close();
}
My WaitForm code
public partial class WaitForm : Form
{
public WaitForm()
{
InitializeComponent();
}
private void WaitForm_Load(object sender, EventArgs e)
{
radWaitingBar1.StartWaiting();
radWaitingBar1.WaitingSpeed = 100;
radWaitingBar1.WaitingStep = 5;
}
}
ShowDialog() is a blocking call, i.e. the current thread will keep waiting on this line until the form is closed (by the user). You should show your WaitForm on a different thread than the main application thread, combined with Invoke() call to ensure that you don't do illegal cross-thread operations. You can use BackgroundWorker component to load and show your WaitForm on a different thread.
Alternately and preferably, you should move your service initialization and running code to the BackgroundWorker. That will ensure you don't need any Invokes.
Example
ServiceReference.Service1Client Server;
WaitForm waitF;
public static void UpdateSNXRATES(object sender, EventArgs e)
{
BackgroundWorker bw = new BackgroundWorker();
bw.WorkerReportsProgress = true;
bw.DoWork += bw_DoWork;
bw.RunWorkerCompleted += bw_RunWorkerCompleted;
bw.RunWorkerAsync();
waitF = new WaitForm();
waitF.ShowDialog();
}
static void bw_DoWork(object sender, DoWorkEventArgs e)
{
Server = new ServiceReference.Service1Client();
Server.ClientCredentials.Windows.ClientCredential.Domain = strDomain;
Server.ClientCredentials.Windows.ClientCredential.UserName = strUser;
Server.ClientCredentials.Windows.ClientCredential.Password = strPassword;
success = Server.UpdateSNXRATES();
}
static void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
waitF.Close()
}

Splash Screen not showing up until all the steps of updating label in it is complete

I have created a splash screen for a WinForm app. Everything works well until the splash screen is just a form with a background image and a label which has a static text - "Loading..."
I want to update the label continuously (with small delay in between) with texts - "Loading","Loading.","Loading.." and "Loading...". For this I have put the following code in my SplashScreen form:
private void SplashScreen_Load(object sender, EventArgs e)
{
lblLoading.Refresh();
lblLoading.Text = "Loading.";
Thread.Sleep(500);
lblLoading.Refresh();
lblLoading.Text = "Loading..";
Thread.Sleep(500);
lblLoading.Refresh();
lblLoading.Text = "Loading...";
Thread.Sleep(500);
}
Now the Splash Screen doesn't appear until the label in it gets updated to "Loading..."
Please help to let me know what I am doing wrong.
Code in my HomeScreen:
public HomeScreen()
{
//....
this.Load += new EventHandler(HandleFormLoad);
this.splashScreen = new SplashScreen();
}
private void HandleFormLoad(object sender, EventArgs e)
{
this.Hide();
Thread thread = new Thread(new ThreadStart(this.ShowSplashScreen));
thread.Start();
//...Performing tasks to be done while splash screen is displayed
done = true;
this.Show();
}
private void ShowSplashScreen()
{
splashScreen.Show();
while (!done)
{
Application.DoEvents();
}
splashScreen.Close();
this.splashScreen.Dispose();
}
EDIT:
As suggested by some users here I have put the startup tasks in background thread and now I am displaying the Splash Screen from the main thread. But still the same issue persist. Here is the updated code of HomeScreen form:
public HomeScreen()
{
//...
this.Load += new EventHandler(HandleFormLoad);
}
private void HandleFormLoad(object sender, EventArgs e)
{
this.Hide();
SplashScreen sc = new SplashScreen();
sc.Show();
Thread thread = new Thread(new ThreadStart(PerformStartupTasks));
thread.Start();
while (!done)
{
Application.DoEvents();
}
sc.Close();
sc.Dispose();
this.Show();
}
private void PerformStartupTasks()
{
//..perform tasks
done = true;
}
and here's the Splash Screen :
private void SplashScreen_Load(object sender, EventArgs e)
{
lblLoading.Update();
lblLoading.Text = "Loading.";
Thread.Sleep(500);
lblLoading.Update();
lblLoading.Text = "Loading..";
Thread.Sleep(500);
lblLoading.Update();
lblLoading.Text = "Loading...";
Thread.Sleep(500);
}
You want a BackgroundWorker that posts ProgressChanged event, which will update the splash screen. The progress changed object could be a string, for example, that you'll display on your splash screen (back on the GUI thread).
You should handle the splash screen in the main thread, and the background work of initialising in the background thread (just as logixologist commented).
That said, the reason that your changed message doesn't show up is because the main thread is busy so it doesn't handle the events that redraws the control. Calling DoEvents in a background thread will only handle messages in that thread, and the messages to update the splash screen is in the main thread.
The Refresh method only invalidates the control, which would cause it to be redrawn if the main thread handled the event. You can use the Update method to force the redraw of the control:
private void SplashScreen_Load(object sender, EventArgs e)
{
lblLoading.Text = "Loading.";
lblLoading.Update();
Thread.Sleep(500);
lblLoading.Text = "Loading..";
lblLoading.Update();
Thread.Sleep(500);
lblLoading.Text = "Loading...";
lblLoading.Update();
}
But, this is only a workaround for the current code. You should really make the main thread handle the messages.
Thanks to all for answering my questions. Finally my issue is solved ! I changed my code such that start-up tasks are now being performed on a separate thread and splash screen is displayed from the Home Screen (main) thread. In the home screen I made use of Backgroundworker to update the 'Loading...' label.
I am posting my code here hoping it may also help someone in future..
For the Home Screen code plz see the EDIT part in my question. Here's the code of Splash Screen :
public SplashScreen()
{
InitializeComponent();
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.WorkerSupportsCancellation = false;
lblLoading.Text = string.Empty;
}
private void SplashScreen_Load(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
while (true)
{
for (int i = 1; i <= 20; i++)
{
System.Threading.Thread.Sleep(200);
worker.ReportProgress(i);
}
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
string dots = string.Empty;
for (int k = 1; k <= e.ProgressPercentage; k++)
{
dots = string.Format("{0}..",dots);
}
lblLoading.Text = ("Loading" + dots);
}
You have to define a background worker in your splash screen form.
Here is an example of what your splash screen could look like :
public partial class SplashScreenForm<T> : Form
{
private BackgroundWorker _backgroundWorker;
private Func<BackgroundWorker, T> _func;
private T _funcResult;
public T FuncResult { get { return _funcResult; } }
public SplashScreenForm(Func<BackgroundWorker, T> func)
{
this._func = func;
InitializeComponent();
this.label1.Text = "";
this._backgroundWorker = new BackgroundWorker();
this._backgroundWorker.WorkerReportsProgress = true;
this._backgroundWorker.DoWork += new DoWorkEventHandler(_backgroundWorker_DoWork);
this._backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(_backgroundWorker_ProgressChanged);
this._backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_backgroundWorker_RunWorkerCompleted);
_backgroundWorker.RunWorkerAsync();
}
private void _backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
var worker = sender as BackgroundWorker;
if (worker != null)
{
_funcResult = this._func.Invoke(worker);
}
}
private void _backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (e.UserState != null)
{
this.label1.Text = e.UserState.ToString();
}
}
private void _backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.Close();
}
}
You can design it the way you want, maybe a pretty gif image, or whatever you can think of.
Call it this way :
private void HandleFormLoad(object sender, EventArgs e)
{
this.Hide();
var splash = new SplashScreenForm<bool>(PerformTask);
splash.ShowDialog(); // function PerformTask will be launch at this moment
this.Show();
}
private bool PerformTask(BackgroundWorker worker)
{
//...Performing tasks to be done while splash screen is displayed
worker.ReportProgress("loading..");
}

Automatically hide one form in C# after many second and show another form

I need to hide current form after many second and then show any form
I'm writing this code but it doesn't work.
namespace tempprj
{
public partial class ProfileFrm : Telerik.WinControls.UI.RadForm
{
public ProfileFrm()
{
InitializeComponent();
}
private void ProfileFrm_Load(object sender, EventArgs e)
{
Frm2 child = new Frm2();
Thread.Sleep(3000);
this.Hide();
child.ShowDialog();
}
}
}
Thread.Sleep(3000);
is going to prevent your project from doing anything at all for 3 seconds (not counting other threads) and freeze the UI. I suggest using the standard .NET timer.
http://msdn.microsoft.com/en-us/library/system.windows.forms.timer.aspx
This is a solution to my question:
private void ProfileFrm_Load(object sender, EventArgs e)
{
timer1.Tick += new EventHandler(timer1_Tick);
timer1.Enabled = true;
timer1.Interval = 4000;
timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
timer1.Stop();
this.Hide();
Frm2 f = new Frm2();
f.ShowDialog();
}

How to stop System.Timers.Timer

I'm using Windows Forms to start a System.Timers.Timer to fire an event every 3 seconds. When I close the form the process keeps firing, and that's fine. The problem happens when I reopen the form to stop the timer on click of a button btnSendOff_Click.
System.Timers.Timer sendTimer = new System.Timers.Timer();
sendTimer.Elapsed += new ElapsedEventHandler(sendProcessTimerEvent);
sendTimer.Interval = 3000;
private void sendProcessTimerEvent(object sender, EventArgs e)
{
MessageBox.Show("Send 3 sec");
}
private void btnSendOn_Click(object sender, EventArgs e)
{
sendTimer.Start();
}
private void btnSendOff_Click(object sender, EventArgs e)
{
sendTimer.Stop();
}
There will be more asynchronous timers on this form. How can I stop this timer when I reopen the form?
The form should not be creating a new timer every time you create a new instance of the form if it needs to keep running after the form closes. The way you have declared the timer, it will create another one each time the form is created. You should put the timer on a different form or declare it in some global module and only make the form activate or deactivate the timer. If the timer needs to keep running when the form is closed, the form should not be the one owning or creating the timer. If the timer doesn't need to keep running when the form is closed, then you should be using a Forms.Timer instead of a System.Timer.
Edit: Add Sample Code
static class Program
{
public static System.Timers.Timer sendTimer;
public static System.Text.StringBuilder accumulatedText;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
sendTimer = new System.Timers.Timer();
accumulatedText = new System.Text.StringBuilder("Started at " + DateTime.Now.ToLongTimeString() + Environment.NewLine);
sendTimer.Interval = 3000;
sendTimer.Elapsed += new System.Timers.ElapsedEventHandler(sendProcessTimerEvent);
Application.Run(new MainForm());
}
static void sendProcessTimerEvent(object sender, System.Timers.ElapsedEventArgs e)
{
accumulatedText.AppendLine("Pinged at " + DateTime.Now.ToLongTimeString());
}
}
class MainForm : Form
{
ToolStrip mainToolStrip = new ToolStrip();
public MainForm()
{
mainToolStrip.Items.Add("Log Control").Click += new EventHandler(MainForm_Click);
Controls.Add(mainToolStrip);
}
void MainForm_Click(object sender, EventArgs e)
{
Form1 frm = new Form1();
frm.ShowDialog();
}
}
class Form1 : Form
{
private Button button1 = new Button();
private TextBox text1 = new TextBox();
public Form1()
{
button1.Dock = DockStyle.Bottom;
button1.Text = Program.sendTimer.Enabled ? "Stop": "Start";
button1.Click += new EventHandler(button1_Click);
text1 = new TextBox();
text1.Dock = DockStyle.Fill;
text1.Multiline= true;
text1.ScrollBars = ScrollBars.Vertical;
text1.Text = Program.accumulatedText.ToString();
Controls.AddRange(new Control[] {button1, text1});
}
void button1_Click(object sender, EventArgs e)
{
Program.sendTimer.Enabled = !Program.sendTimer.Enabled;
button1.Text = Program.sendTimer.Enabled ? "Stop" : "Start";
}
}

Categories

Resources