C# Get Textbox value in backgroundworker dowork event - c#

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
...
}

Related

how to report about method situation via progress bar wpf C#

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;
}

how to return from the background worker to web UI in asp.net

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");
}

How to wait two BackgrandWorker's RunWorkerCompleted event finished?

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();
}

UI not updating despite use of BackgroundWorker

I am setting the .Text value of a textbox, disabling it, and then calling a BackgroundWorker to do a lengthy filesystem operation. The textbox does not update with the new text value until about halfway through the BackgroundWorker operation.
What can I do to force the texbox to show the new text value ASAP? Relevant code below:
void BeginCacheCandidates()
{
textBox1.Text = "Indexing..."; // <-- this does not update until about 20 to 30 seconds later
textBox1.Enabled = false;
backgroundWorker1.RunWorkerAsync();
}
void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
//prime the cache
CacheCandidates(candidatesCacheFileName);
}
void backgroundWorker1_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
textBox1.Text = "";
textBox1.Enabled = true;
textBox1.Focus();
}
Update: I resolved the issue. It was code unrelated to this - I had overridden WndProc and it was going into a loop...
Unless there's some detail I'm missing, wouldn't ReportProgress give you what you want?
void BeginCacheCandidates()
{
textBox1.Text = "Indexing...";
textBox1.Enabled = false;
backgroundWorker1.ReportProgress += new ProgressChangedEventHandler(handleProgress)
backgroundWorker1.RunWorkerAsync();
}
void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
//prime the cache
backgroundWorker1.ReportProgress(<some int>, <text to update>);
CacheCandidates(candidatesCacheFileName);
}
void handleProgress(object sender, ProgressChangedEventArgs e)
{
...
textBox1.Text = e.UserState as String;
...
}
Try invoking the change on the textbox instead of directly calling it.
textBox1.BeginInvoke(new MethodInvoker(() => { textBox1.Text = string.Empty; }));
This will cause the change to happen on the Form's thread.
Use Form.Update() method to force UI updates.
void BeginCacheCandidates()
{
textBox1.Text = "Indexing..."; // <-- this does not update until about 20 to 30 seconds later
textBox1.Enabled = false;
this.Update(); // Force update UI
backgroundWorker1.RunWorkerAsync();
}

why is this backgroundworker code causing this error: Parameter count mismatch

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.

Categories

Resources