I have a handler that returns some string messages. How can i put them into a form application? I mean I would like each time the handler is activated to print the result in a windows form. I now i need to use thread. I don't know how can i programatically create and add changes the name of the forms that pop up when a message is handled. Can someone please tell me how to do it?
I asssume that you have some work you want to do in the background and whenever an amount of progress is don you want to update the form...
Then I would use the backgroundworker:
BackgroundWorker bw = new BackgroundWorker();
public Form1()
{
InitializeComponent();
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
}
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)); //Activating the progressChanged event
}
}
}
Whenever you execute worker.ReportProgress() the event below will fire on the UI thread which is giving you the dynamic updates you wanted
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.tbProgress.Text = (e.ProgressPercentage.ToString() + "%");
}
When the worker is finished executing the RunWorkerCompleted event will fire
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!";
}
}
Source
Related
The Problem
I have used the project from https://github.com/zaagan/BioMetrix and want to use BackgroundWorker to display a progression during long tasks (Ex: Get Log Data takes about 30 seconds)
What I've done so far
1- Added backgroundWorker1 from Toolbox
2- After InitializeComponent(), I've Added :
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.WorkerSupportsCancellation = true;
3- Added those functions:
private void backgroundWorker1_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
{
System.Threading.Thread.Sleep(500);
worker.ReportProgress(i * 10);
}
}
}
private void backgroundWorker1_ProgressChanged(object sender,
ProgressChangedEventArgs e)
{
this.Text = (e.ProgressPercentage.ToString() + "%");
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled == true)
{
this.Text = "Canceled!";
}
else if (e.Error != null)
{
this.Text = "Error: " + e.Error.Message;
}
else
{
this.Text = "Done!";
}
}
I was expecting to view the progression percentage on the main Caption title text while retrieving log data from the device.
You need to assign the event handler to the event
worker.DoWork += backgroundWorker_ProgressChanged;
If you have created a Windows Form you need to looking in events page of the Background Worker properties and find the DoWork event, then assign it a function to run.
i am working on project in C# and its contain a methods that need a long time to be executed so i need a progress bar that tell the user about how much remain and i don't know how .
i google for it and i see courses about BackgroundWorker and still don't know how to use it
private void Lock_Methods()
{
foreach (FolderInfo fi in FolderInfo)
{
// code need a lot of time ....
}
}
any help please ...
Declare
var bw = new BackgroundWorker()
{ WorkerReportsProgress = true };
bw.RunWorkerAsync();
bw.DoWork += bw_DoWork;
bw.ProgressChanged += bw_ProgressChanged;
And
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
for(int i = 0: i < FolderInfo.Count; i++)
{
//...
(sender as BackgroundWorker).ReportProgress((int)(100/FolderInfo.Count)*i, null);
}
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
I want to know how to show image loading progress in progress-bar in win form.
my code is
private void Form2_Load(object sender, EventArgs e)//load form and get profile and avatar
{
backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
label2.Text = "Avatar Loaded";
}
private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)//showing progress
{
if (InvokeRequired)
{
BeginInvoke(new Action(() => backgroundWorker1_ProgressChanged(sender, e)));
}
else
{
if (progressBarX1.Value != e.ProgressPercentage)
{
progressBarX1.Value = e.ProgressPercentage;
progressBarX1.Refresh();
}
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)//loading avatar
{
WebClient wc = new WebClient();
Stream stream = wc.OpenRead("http://avatar.nimbuzz.com/getAvatar?jid=" + textBox1.Text);
pictureBox1.Image = (Image.FromStream(stream));
}
The image loads successfully but do not show any progress in progress-bar
Well, i would use the ProgressChanged Event from a WebClient to get the result of how far the download progress actually is. Then you can't save it from the thread of the backgroundworker, so you gotta do this when you have the file.
UPDATED
private BackgroundWorker bgw;
private void Form1_Load(object sender, EventArgs e)
{
bgw = new BackgroundWorker();
bgw.DoWork += bgw_DoWork;
bgw.WorkerReportsProgress = true;
bgw.RunWorkerCompleted += bgw_RunWorkerCompleted;
bgw.ProgressChanged += bgw_ProgressChanged;
bgw.RunWorkerAsync();
}
void bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
pictureBox1.Image = (Image)e.Result;
}
void bgw_DoWork(object sender, DoWorkEventArgs e)
{
WebClient wc = new WebClient();
wc.DownloadProgressChanged += wc_DownloadProgressChanged;
Stream stream = wc.OpenRead("" + textBox1.Text);
e.Result = (Image.FromStream(stream));
}
void wc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
bgw.ReportProgress(e.ProgressPercentage);
}
The problem with your code is that backgroundWorker1_ProgressChanged() is called in the context of the worker thread but UI updates can only be done within the UI thread (main thread). In your scenario you must call:
progressBarX1.Value = e.ProgressPercentage;
within the UI thread. There are many ways how to do this but a simple one is to use InvokeReqzired() to check if you are in the UI thread and you are not then call BeginInvoke() to send the execution of that command to the UI-/main-thread. The following should do the trick:
private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
if (InvokeRequired)
{
BeginInvoke(new Action(() => backgroundWorker1_ProgressChanged(sender, e)));
}
else
{
progressBarX1.Value = e.ProgressPercentage;
}
}
Update:
I would also change:
backgroundWorker1.RunWorkerAsync();
backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
to:
backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
backgroundWorker1.RunWorkerAsync();
so the progress event is assigned (and therefore in place) before starting the asynchronous work. Otherwise you may miss a progress call.
Update 2:
You also need the following line to execute in the UI thread:
pictureBox1.Image = (Image.FromStream(stream));
To do so use the Completed event of BackgroundWorker and bass the image data using the result parameter. Then in the eventhandler use InvokeRequired() and BeginInvoke() just like in the Progress event).
Uodate 3:
Remeins unchanged is good as you don't get a crash because of not calling UI stuff in the UI thread ;-)
Try to force a repaint on the control by calling:
progressBarX1.Refresh();
(just after you assigned a new value to it).
So the code in the progress event looks like this:
private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
if (InvokeRequired)
{
BeginInvoke(new Action(() => backgroundWorker1_ProgressChanged(sender, e)));
}
else
{
if (progressBarX1.Value != e.ProgressPercentage)
{
progressBarX1.Value = e.ProgressPercentage;
progressBarX1.Refresh();
}
}
}
If that still doesn't work check that your main/UI thread is not blocked or totally busy.
Update 4:
Just to make sure: you need to enable progress-reporting on the background worker and call its ReportProgress() method from time to time within the backgroundWorker1_DoWork(). See the following MS-Tutorial for more information on usage of the BackgroundWorker: http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx
Enabling progress reporting on a backgroundworker:
backgroundWorker1.WorkerReportsProgress = true;
or use the form-designer and set the property WorkerReportsProgress to True. Then you still need to call the backgroundWorker1.ReportProgress() from time to time.
Update 5:
Ok, lets give it a complete try. I've checked some reference docs from MS so in case of the backgroundworker ProgressChanged and Completed events you don't need to BeginInvoke() them as MS does this already for you.
private void Form2_Load(object sender, EventArgs e)
{
getto();
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.ProgressChanged -= backgroundWorker1_ProgressChanged;
backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged;
backgroundWorker1.RunWorkerCompleted -= backgroundWorker1_Completed;
backgroundWorker1.RunWorkerCompleted += backgroundWorker1_Completed;
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
using (var wc = new WebClient())
{
wc.DownloadProgressChanged += (sender, e) => backgroundWorker1.ReportProgress(sender, e);
using (var stream = wc.OpenRead("http://avatar.nimbuzz.com/getAvatar?jid=" + textBox1.Text))
{
e.Result = (Image.FromStream(stream));
}
}
}
private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
progressBarX1.Value = e.ProgressPercentage;
progressBarX1.Refresh();
}
private void backgroundWorker1_Completed(object sender, DoWorkEventArgs e)
{
pictureBox1.Image = e.Result;
}
This is how I create a thread that does domething reps times:
protected virtual void RedButtonClicked(object sender, System.EventArgs e)
{
Nuker n = new Nuker(target, reps);
bombThread = new Thread(new ThreadStart(n.nuke));
bombThread.Start();
}
The thread class:
public class Nuker
{
private string target;
private int reps;
//...
public void nuke()
{
for(int i=0; i<reps; ++i)
{
ICBM.nuke(target);
Thread.Sleep(5500);
}
System.Console.WriteLine("Done.");
}
}
(I create a new class to store some variables since I can't pass these in ThreadStart().)
Now I would like to have a simple visualisation of the process, let's say printing the current repetition in a text field on a form. How would I use the i from the loop to do that?
In the simplest form you proved a callback in the Nuker class
public Nuker(string target, int reps, Action reportCallback){..}
In the loop you just call reportCallback(i);
Nuker n = new Nuker(target, reps, ReportMethod);
with
private void ReportMethod(int currentIdx)
{
if (InvokeRequired) // Invoke if UI update
...
}
But, probably you want to use the BackgroundWorker that has build in methods for reporting progress on the UI thread. Just check the examples on MSDN.
you can do it with a backgroundworker, it´s one of the easiest threads :-)
below i have post you a sample that i have createt to teach some friends the use of the backgroundworker ;-)
private BackgroundWorker bw = new BackgroundWorker();
public Form1()
{
InitializeComponent();
bw.WorkerReportsProgress = true;
bw.WorkerSupportsCancellation = true;
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
}
public void buttonStart_Click(object sender, EventArgs e)
{
if (bw.IsBusy != true)
bw.RunWorkerAsync(12); //Start
}
public int Pils(int i)
{
Thread.Sleep(2000);
bw.ReportProgress(70, "In the middle of the work..");
Thread.Sleep(2000);
bw.ReportProgress(90, "Returning the result..");
Thread.Sleep(2000);
return (2 * i);
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
bw.ReportProgress(20, "Waiting for cancel..");
Thread.Sleep(2000);
if ((bw.CancellationPending == true))
e.Cancel = true;
else
{
bw.ReportProgress(50, "Starting process..");
e.Result = Pils((int)e.Argument);
}
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
bw.ReportProgress(100, "Work done..");
if ((e.Cancelled == true))
textBox1.Text = "Canceled!";
else if (e.Error != null)
textBox1.Text = ("Error: " + e.Error.Message);
else textBox1.Text = e.Result.ToString();
}
private void buttonCancel_Click(object sender, EventArgs e)
{
if (bw.WorkerSupportsCancellation == true)
bw.CancelAsync();
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
listBox1.Items.Add((e.ProgressPercentage.ToString() + "%") + " - " + e.UserState as String);
}
url to the blogpost: link
I have a background worker. Before I invoke the worker I disable a button and make a gif visible. I then invoke the runworkerasync method and it runs fine until comleteion. On the 'RunWorkerCompleted()' I get a cross thread error. Any idea why?
private void buttonRun_Click(object sender, EventArgs e)
{
if (comboBoxFiscalYear.SelectedIndex != -1 && !string.IsNullOrEmpty(textBoxFolderLoc.Text))
{
try
{
u = new UpdateDispositionReports(
Convert.ToInt32(comboBoxFiscalYear.SelectedItem.ToString())
, textBoxFolderLoc.Text
, Properties.Settings.Default.TemplatePath
, Properties.Settings.Default.ConnStr);
this.buttonRun.Enabled = false;
this.pictureBox1.Visible = true;
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
bw.RunWorkerAsync();
//backgroundWorker1.RunWorkerAsync();
}
catch (Exception ex)
{
MessageBox.Show("Unable to process.\nError:" + ex.Message, Properties.Settings.Default.AppName);
}
}
}
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
buttonRun.Enabled = true;
pictureBox1.Visible = false;
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
u.Execute();
}
It seems to be an issue with VSTO and BackgroundWorker.
The solution is here.
Basically you need to call
System.Threading.SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext());
before you call RunWorkerAsync. Works great.
To avoid instantiating the object every time you may have a static member in you AddIn's main class and reuse it. This way you only instantiate once.
something about VSTO running the background worker on the same thread as the controls. Not sure. I had to check the InvokeRequired
private void buttonRun_Click(object sender, EventArgs e)
{
if (comboBoxFiscalYear.SelectedIndex != -1 && !string.IsNullOrEmpty(textBoxFolderLoc.Text))
{
try
{
u = new UpdateDispositionReports(
Convert.ToInt32(comboBoxFiscalYear.SelectedItem.ToString())
, textBoxFolderLoc.Text
, Properties.Settings.Default.TemplatePath
, Properties.Settings.Default.ConnStr);
this.buttonRun.Enabled = false;
this.pictureBox1.Visible = true;
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
bw.RunWorkerAsync();
//backgroundWorker1.RunWorkerAsync();
}
catch (Exception ex)
{
MessageBox.Show("Unable to process.\nError:" + ex.Message, Properties.Settings.Default.AppName);
}
}
}
delegate void ReenableRunCallback();
private void ReenableRun()
{
if (this.buttonRun.InvokeRequired)
{
ReenableRunCallback r = new ReenableRunCallback(ReenableRun);
this.buttonRun.Invoke(r, null);
}
else
this.buttonRun.Enabled = true;
}
private void HideProgress()
{
if (this.pictureBox1.InvokeRequired)
{
ReenableRunCallback r = new ReenableRunCallback(HideProgress);
this.pictureBox1.Invoke(r, null);
}
else
this.pictureBox1.Visible = false;
}
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
ReenableRun();
HideProgress();
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
u.Execute();
}