That's the code:
private void button1_Click(object sender, EventArgs e)
{
ParaClass pcs = new ParaClass();
pcs.strPath = textBox1.Text;
pcs.sendedGrid = ugSrc;
this.backgroundWorker1.RunWorkerAsync(pcs);
ParaClass pcsB = new ParaClass();
pcsB.strPath = textBox2.Text;
pcsB.sendedGrid = ultraGrid2;
this.backgroundWorker2.RunWorkerAsync(pcsB);
doSomething();
}
and in both backgrandworker1 & backgrandworker2 ' complet event ,i write code like this:
private void backgroundWorker1_RunWorkerCompleted(object sender,RunWorkerCompletedEventArgs e)
{
doSomethingelsebk1();
}
private void backgroundWorker2_RunWorkerCompleted(object sender,RunWorkerCompletedEventArgs e)
{
doSomethingelsebk2();
}
now the problem is : the function doSomething() in button1's click event must wait both backgrandworker's complete event finish.
if i change doSomething() to
private void backgroundWorker2_RunWorkerCompleted(object sender,RunWorkerCompletedEventArgs e)
{
doSomethingelsebk2();
doSomething();
}
then,because there are two thread,i don't know which thread will finish first,so what is the solution
Create 2 flags which represent complete state of 2 BackgroundWorker.
Turn each flag on in the RunWorkerCompleted event, then call doSomething() method.
In doSomething method, check if both flags is on, then continue to do, otherwise, return.
Create 2 AutoResetEvents, set them when each Background worker finishes and wait for them all in the main method with a WaitHandle.
WaitHandle[] handles = new WaitHandle[] { new AutoResetEvent(false), new AutoResetEvent(false)};
private void button1_Click(object sender, EventArgs e)
{
ParaClass pcs = new ParaClass();
pcs.strPath = textBox1.Text;
pcs.sendedGrid = ugSrc;
this.backgroundWorker1.RunWorkerAsync(pcs);
ParaClass pcsB = new ParaClass();
pcsB.strPath = textBox2.Text;
pcsB.sendedGrid = ultraGrid2;
this.backgroundWorker2.RunWorkerAsync(pcsB);
WaitHandle.WaitAll(this.handles);
doSomething();
}
private void backgroundWorker1_RunWorkerCompleted(object sender,RunWorkerCompletedEventArgs e)
{
doSomethingelsebk1();
((AutoResetEvent)this.handles[0]).Set();
}
private void backgroundWorker2_RunWorkerCompleted(object sender,RunWorkerCompletedEventArgs e)
{
doSomethingelsebk2();
((AutoResetEvent)this.handles[1]).Set();
}
Related
I have a problem with backgroundworker. I wrote program to copying files from local disc to network disk and I want to shows progressbar spinning in circles (not shows progress) when process is running.When I set backgroundworker into empty button everything works fine, but when I set backgroundworker into button which have function to coping files progressbar shows when copying process is finished. Why and how can I solved that? Below code.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
circularProgressBar1.BeginInvoke(new MethodInvoker(sd));
}
public void sd()
{
circularProgressBar1.Visible = true;
circularProgressBar1.Enabled = true;
circularProgressBar1.Style = ProgressBarStyle.Marquee;
}
private void backgroundWorker1_ProgressChanged(object sender,
ProgressChangedEventArgs e)
{
circularProgressBar1.Value = e.ProgressPercentage;
}
private void backgroundWorker1_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
MessageBox.Show("End");
}
private void button1_Click_1(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void copy_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
List<string> pathList = new List<string>();
// for example add 1000 path
pathList.add("C:\test\2.jpg");
pathList.add("C:\test\3.jpg");
foreach(string in in pathList)
{
File.Copy(in,"D:\test2",true);
}
}
You need to put the File.Copy in backgroundWorker1_DoWork - this is where the background work is done.
You may activate the circularProgressBar before the call to backgroundWorker1.RunWorkerAsync and disable it in backgroundWorker1_RunWorkerCompleted.
background worker in asp.net does not write the content to the web UI when background worker completed. please tell me the reasons why. and how to recover.???
static BackgroundWorker bwProcess;
[WebMethod()]
public static int GetProgress()
{
return Percentage;
}
background worker starts when click event happen
protected void btnClick_Click(object sender, EventArgs e)
{
bwProcess = new BackgroundWorker
{
WorkerReportsProgress = true,
WorkerSupportsCancellation = true
};
bwProcess.DoWork += new DoWorkEventHandler(bwProcess_DoWork);
bwProcess.ProgressChanged += new ProgressChangedEventHandler(bwProcess_ProgressChanged);
bwProcess.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bwProcess_RunWorkerCompleted);
bwProcess.RunWorkerAsync("AsyncWorker");
}
do work event for the backgroundworker
void bwProcess_DoWork(object sender, DoWorkEventArgs e)
{
bwProcess.ReportProgress(1);
for (int i = 0; i <= 100; i++)
{
if (bwProcess.CancellationPending)
{
e.Cancel = true;
return;
}
bwProcess.ReportProgress(i);
Thread.Sleep(20);
}
e.Result = "100 %";
}
this part is not working. it run nut there is no response
void bwProcess_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Response.WriteFile("D:\\Samples.xlsx");
}
You've passed something to e.Result in DoWork, but you don't anything with it in RunWorkerCompleted.
void bwProcess_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
var text = e.Result as string;
Response.Write(text);
Response.WriteFile("D:\\Samples.xlsx");
}
This question already has answers here:
How do I update the GUI from another thread?
(47 answers)
Closed 8 years ago.
I am using UI with multiple buttons and I need to start background task on button click and report back to main thread + update UI when the task is finished.
This is currently part of my code:
private void button1Click(object sender, EventArgs e)
{
button1.Text = "Starting";
button1.Enabled = false;
button1Worker.RunWorkerAsync();
}
private void button1worker_DoWork(object sender, DoWorkEventArgs e)
{
toolStarter.startTool("button1");
}
private void button1worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
button1.Text = "Autoruns";
button1.Enabled = true;
}
This solution works as intended / expected, however the same code is repeated for 15 different buttons and that seem to be wrong to me.
Can you recommend some other way to do the same thing?
I did try ThreadPool queue but did not manage to update UI after task finished.
You can do this via async/await instead, which simplifies the code and eliminates the need for the background worker(s):
private async void button1Click(object sender, EventArgs e)
{
button1.Text = "Starting";
button1.Enabled = false;
await Task.Run(() => toolStarter.startTool("button1"));
button1.Text = "Autoruns";
button1.Enabled = true;
}
If your buttons are all doing the same operation, with only the string changing, you can refactor this out to support that:
private async Task ExecuteButton(Button button, string toolName)
{
button.Text = "Starting";
button.Enabled = false;
await Task.Run(() => toolStarter.startTool(toolName));
button.Text = "Autoruns";
button.Enabled = true;
}
private async void button1Click(object sender, EventArgs e)
{
await ExecuteButton(button1, "button1");
// Do any other specific stuff for after here
}
// Use for other buttons as needed
private async void button2Click(object sender, EventArgs e)
{
await ExecuteButton(button2, "button2");
}
// This is your helper class that actually does the work
public class ToolStarter
{
public void startTool(string name)
{
// Put your switch statement here to decide what work to do
}
}
public class ButtonWorker
{
private Button button;
private ToolStarter toolStarter;
public ButtonWorker(Button button, ToolStarter toolStarter)
{
this.button = button;
this.toolStarter = toolStarter;
this.button.Enabled = false;
this.button.Text = "Starting";
ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork));
}
private void DoWork(object state)
{
this.toolStarter.startTool(button.Name);
// Pass control back to the UI thread so you can update your
// button text and enabled/status
this.button.Invoke(new Action(() =>
{
this.button.Text = "Autoruns";
this.button.Enabled = true;
}));
}
}
// This is just showing you how to use the ButtonWorker
public class ButtonWorkerTest
{
public ButtonWorkerTest()
{
var btn1 = new Button { Name = "button1" };
var btn2 = new Button { Name = "button2" };
var toolstarter = new ToolStarter(); // This is your class
var worker1 = new ButtonWorker(btn1, toolstarter);
var worker2 = new ButtonWorker(btn2, toolstarter);
}
}
In my windows forms application I have a textbox and backgroundworker component. In dowork event of the backgroundworker I am trying to access value of the textbox. How can i do that? I'm getting following exception in dowork event handler code when I try to access value of the textbox:
Cross-thread operation not valid: Control 'txtFolderName' accessed from a thread other than the thread it was created on`
You can only access textbox / form controls in GUI thread, you can do so like that.
if(txtFolderName.InvokeRequired)
{
txtFolderName.Invoke(new MethodInvoker(delegate { name = txtFolderName.text; }));
}
try this
txtFolderName.Invoke((MethodInvoker)delegate
{
string strFolderName = txtFolderName.Text;
});
You need to use MethodInvoker. Like:
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += delegate(object sender, DoWorkEventArgs e)
{
MethodInvoker mi = delegate { txtFolderName.Text = "New Text"; };
if(this.InvokeRequired)
this.Invoke(mi);
};
You will have to invoke your TextBox on the main thread.
tb.Invoke((MethodInvoker) delegate
{
tb.Text = "Update your text";
});
Try This:
void DoWork(...)
{
YourMethod();
}
void YourMethod()
{
if(yourControl.InvokeRequired)
yourControl.Invoke((Action)(() => YourMethod()));
else
{
//Access controls
}
}
Hope This Help.
this is the another 2 methods i use.
//save the text value of txtFolderName into a local variable before run the backgroundworker.
string strFolderName;
private void btnExe_Click(object sender, EventArgs e)
{
strFolderName = txtFolderName.text;
backgroundworker.RunWorkerAsync();
}
private void backgroundworker_DoWork(object sender, DoWorkEventArgs e)
{
backgroundworkerMethod(strFolderName);//get the value from strFolderName
...
}
----------------------------------------------------
private void btnExe_Click(object sender, EventArgs e)
{
backgroundworker.RunWorkerAsync(txtFolderName.text);//pass the value into backgroundworker as parameter/argument
}
private void backgroundworker_DoWork(object sender, DoWorkEventArgs e)
{
backgroundworkerMethod(e.Argument.ToString());//get the value from event argument
...
}
what is wrong with this code below? The conn_PageDeleted is coming from a background thread and i am trying to update a label every time i get a call back. I get an error stating
Parameter count mismatch.
Here is the code:
private void cmdDeletePage_Click(object sender, EventArgs e)
{
worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
worker.RunWorkerAsync();
}
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
lblDeleteStatus.Text = "";
MessageBox.Show("Complete");
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
Connecter conn = new Connecter("a", "m");
conn.PageDeleted += new Connecter.PageDeletedHandler(conn_PageDeleted);
bool success = conn.DeletePage(txtPageToDelete.Text, chkRecursive.Checked);
}
public delegate void UpdateLabelHandler(object sender, string name);
void conn_PageDeleted(object sender, string name)
{
if (this.InvokeRequired)
{
this.BeginInvoke(new UpdateLabelHandler(UpdateMe));
}
else
{
lblDeleteStatus.Text = name;
}
}
private void UpdateMe(object sender_, string name_)
{
lblDeleteStatus.Text = name_;
}
You should pass the parameters to the UpdateMe method, try this:
void conn_PageDeleted(object sender, string name)
{
if (this.InvokeRequired)
{
this.BeginInvoke(new UpdateLabelHandler(UpdateMe), new object[] {sender, name}); //<-- the update goes here
}
else
{
lblDeleteStatus.Text = name;
}
}
Your delegate has to match the signature of the event handler, something like this:
public delegate void UpdateLabelHandler(object sender, string strArgs);
Edit: Since you have edited the code to include this ... I will amend this accordingly....
Looking at your edited code, I have to question this:
void worker_DoWork(object sender, DoWorkEventArgs e)
{
Connecter conn = new Connecter("a", "m");
conn.PageDeleted += new Connecter.PageDeletedHandler(conn_PageDeleted);
bool success = conn.DeletePage(txtPageToDelete.Text, chkRecursive.Checked);
}
You are wiring up a 'PageDeleted' event handler....and call 'DeletePage' method after it, I presume that in turn invokes the event handler 'conn_PageDeleted' within the 'DoWork' body, it goes out of scope when the 'BackgroundWorker' thread is finished...and since 'conn' is in local scope of the 'worker_DoWork' method, that gets destroyed, and somehow your event handler gets messed up! Can you confirm this?
Hope this helps,
Best regards,
Tom.