Reputation: 1269
I am attempting to use a Background Worker in order to add a Cancel button to my winform.
I have added the below syntax, but the textbox is never updated with any progress as it was before I tried to implement the background worker.
public Form1()
{
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
string resourceName = new AssemblyName(args.Name).Name + ".dll";
string resource = Array.Find(this.GetType().Assembly.GetManifestResourceNames(), element => element.EndsWith(resourceName));
using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resource))
{
Byte[] assemblyData = new Byte[stream.Length];
stream.Read(assemblyData, 0, assemblyData.Length);
return Assembly.Load(assemblyData);
}
};
InitializeComponent();
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.WorkerSupportsCancellation = true;
}
private void btnQuery_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
//Iterating the array
foreach (string s in sxc)
{
txt_ProgressDetails.Visible = true;
AppendTextBoxLine("Getting Data For " + s);
//Put data into DataTable
PopulateDT(s);
}
//If the cancel button was pressed
if (backgroundWorker1.CancellationPending)
{
e.Cancel = true;
return;
}
}
private void AppendTextBoxLine(string statusMessage)
{
if (txt_ProgressDetails.Text.Length > 0)
txt_ProgressDetails.AppendText(Environment.NewLine);
txt_ProgressDetails.AppendText(statusMessage);
}
Upvotes: 2
Views: 451
Reputation: 821
The Do_Work event of BackgroundWorker runs in a non-STA thread and you can't update UI from there. You can rewrite your code to update UI elements from the thread that created them with InvokeRequred
and Invoke
method.
Add this to your Form:
delegate void UpdateUICallback(string statusMessage);
And Change your AppendTextBoxLine
method to this:
if (InvokeRequired)
{
UpdateUICallback d = new UpdateUICallback(AppendTextBoxLine);
this.Invoke(d, new object[] {statusMessage});
}
else
{
if (txt_ProgressDetails.Text.Length > 0)
txt_ProgressDetails.AppendText(Environment.NewLine);
txt_ProgressDetails.AppendText(statusMessage);
}
so your code will look like this:
public Form1()
{
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
string resourceName = new AssemblyName(args.Name).Name + ".dll";
string resource = Array.Find(this.GetType().Assembly.GetManifestResourceNames(), element => element.EndsWith(resourceName));
using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resource))
{
Byte[] assemblyData = new Byte[stream.Length];
stream.Read(assemblyData, 0, assemblyData.Length);
return Assembly.Load(assemblyData);
}
};
InitializeComponent();
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.WorkerSupportsCancellation = true;
}
private void btnQuery_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
//Iterating the array
foreach (string s in sxc)
{
txt_ProgressDetails.Visible = true;
AppendTextBoxLine("Getting Data For " + s);
//Put data into DataTable
PopulateDT(s);
}
//If the cancel button was pressed
if (backgroundWorker1.CancellationPending)
{
e.Cancel = true;
return;
}
}
delegate void UpdateUICallback(string statusMessage);
private void AppendTextBoxLine(string statusMessage)
{
if (InvokeRequired)
{
UpdateUICallback d = new UpdateUICallback(AppendTextBoxLine);
this.Invoke(d, new object[] {statusMessage});
}
else
{
if (txt_ProgressDetails.Text.Length > 0)
txt_ProgressDetails.AppendText(Environment.NewLine);
txt_ProgressDetails.AppendText(statusMessage);
}
}
Upvotes: 2