I read both BackgroundWorker still freezes UI and UI still freezes using backgroundWorker but neither have helped me solve my issue. I asked a question a few days ago about Datatable not displaying information after SQL query fill in backgroundworker, which I eventually solved by using Invoke and a delegate.
My current code (shown below) gives me the results I want, except for two things: it doesn't actually display the progress bar (at least that I can see) and it freezes the UI while running:
DataTable tab1table = new DataTable();
public Form1()
{
InitializeComponent();
Instantiatesearch1Thread();
}
private void Instantiatesearch1Thread()
{
search1Thread.WorkerReportsProgress = true;
search1Thread.WorkerSupportsCancellation = true;
search1Thread.ProgressChanged += search1Thread_ProgressChanged;
search1Thread.DoWork += search1Thread_Dowrk;
search1Thread.RunWorkerCompleted += search1Thread_RunWorkerCompleted;
}
private void sbutton1_Click(object sender, EventArgs e)
{
search1Thread.RunWorkerAsync();
}
void search1Thread_Dowrk(object sender, DoWorkEventArgs e)
{
int percentprogress = 0;
var worker = sender as BackgroundWorker;
// Ensure process is thread-safe by using Invoke method
Invoke(new MethodInvoker(delegate
{
// Search1 button event handler
using (SqlConnection conn = new SqlConnection(Connection_Info))
{
conn.Open();
using (SqlDataAdapter cmd = new SqlDataAdapter(comboBox1SQL, conn))
{
//MessageBox.Show("Working");
if (comboBox1.Text.Contains("ID"))
{
long para = long.Parse(search1.Text);
cmd.SelectCommand.Parameters.Add(new SqlParameter
{
ParameterName = "#combo1Par",
Value = para,
SqlDbType = SqlDbType.BigInt
});
}
// Clear datatable if it contains any information and then fill it
if (tab1table != null)
tab1table.Clear();
cmd.Fill(tab1table);
// Set Progress Bar info
search1Progress.Maximum = tab1table.Rows.Count;
groupBox2.Controls.Add(search1Progress);
search1Progress.BringToFront();
}
}
// This is a long calculation where I am reporting the
// progress every iteration (which is probably not helping,
// but didn't change anything when commented out).
if(!String.IsNullOrEmpty(search1.Text) && tab1Combo1.SelectedIndex > -1 || tab1Combo2.SelectedIndex > -1)
{
for (int i = tab1table.Rows.Count - 1; i >= 0; i--)
{
DataRow dr = tab1table.Rows[i];
if (!dr.ItemArray.Contains(search1.Text.ToString()))
{
dr.Delete();
tab1table.AcceptChanges();
}
percentprogress++;
worker.ReportProgress(percentprogress);
}
}
}));
}
void search1Thread_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
search1Progress.Value = e.ProgressPercentage;
}
void search1Thread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
tab1datatable.DataSource = null;
tab1datatable.DataSource = tab1table;
tab1datatable.Update();
groupBox2.Controls.Remove(search1Progress);
MessageBox.Show(" Your search returned " + tab1table.Rows.Count.ToString() + " results");
}
Can anyone point out what I am doing wrong here?
My issue may have something to do with Invoke as I know it's not the best method with BackgroundWorker, but I couldn't get it to update the UI using any other method.
Related
Im working with WinForms.
I want to populate ListView from background thread but when im Invoking listview my program stops and shows an error. The error is "Cannot acces a disposed object. Object name is: ListView." And when i put this method
lvValidate.Invoke((Action)delegate
{
lvValidate.Items.Add(listitem);
});
in a try-catch block my program starts lagging. I dont know where is the problem,but my Invoke method is:
static class Intercept
{
internal static void Invoke(this Control control, Action action)
{
control.Invoke(action);
}
}
The error only showing when i close the form and open another form (in the same program). In the Form which contains the ListView the data is unreadable and it seems loads a thousands times.
Here's what my DoWork,ProgressChanged,RunWorkerCompleted event does.
private void bgwLoad_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
string commandText = "SELECT * FROM works";
MySqlCommand command = new MySqlCommand(commandText, connection);
MySqlDataAdapter da = new MySqlDataAdapter(command);
connection.Close();
connection.Open();
reader = command.ExecuteReader();
connection.Close();
DataTable dt = new DataTable();
da.Fill(dt);
for (int i = 0; i < dt.Rows.Count; i++)
{
DataRow dr = dt.Rows[i];
ListViewItem listitem = new ListViewItem(dr["ID"].ToString(), dr["Date"].ToString());
listitem.SubItems.Add(dr["Date"].ToString());
listitem.SubItems.Add(dr["Name"].ToString());
listitem.SubItems.Add(dr["WorkNumber"].ToString());
listitem.SubItems.Add(dr["WorkCode"].ToString());
listitem.SubItems.Add(dr["CoreThread"].ToString());
listitem.SubItems.Add(dr["Tech"].ToString());
listitem.SubItems.Add(dr["From"].ToString());
listitem.SubItems.Add(dr["To"].ToString());
listitem.SubItems.Add(dr["Validate"].ToString());
listitem.SubItems.Add(dr["Validate2"].ToString());
lvValidate.Items.Add(listitem);
}
}
private void bgwLoad_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
}
private void bgwLoad_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
picLoading.Visible = false;
}
Try the following:
Dispatcher.CurrentDispatcher.Invoke(() => {
lvValidate.Items.Add(listitem);
});
EDIT:
Or Try this:
public static void AddItem(ListItem listitem)
{
if (lvValidate.InvokeRequired)
{
AddItemDelegate d = new AddItemDelegate (AddItem);
lvValidate.Invoke(d, new object[] { listitem });
}
else
{
lvValidate.Invoke(new Action(() =>
{
lvValidate.Items.Add(listitem);
}));
}
}
delegate void AddItemDelegate(ListItem listitem);
Then call:
AddItem(listitem);
According to your comments, you are trying to retrieve Data from a DB using a DataAdapter, then handing out the Data piecemeal. This will not work for several reasons:
DataAdapter
The DataAdapter Classes all have in common that they only work, while the DBConnection is actively open. That is why you get "Cannot acces a disposed object". Because by the time you try to use it, it the connection is already Disposed. And disposing is not a thing you should ever delay. Or split up at all. Keep the using (that you hopefully got) right where it is, inside the DoWork().
For that reason you always have to copy the data of the DataAdapter into a non-Adapter collection. Really any old list would do. This will temporarily double the Memory load and might procude some stuff for the GC to clean up, but is really they only adviseable way.
Bulk Writes only in Completed
While you can theoretically hand out Partial Reads/process results via Progress Reporting, this is not adviseable to try. Writing a GUI has a massive overhead. The first and only time I did that, I ended up locking up my GUI thread with Write and Draw Operations. It looked like I had never done Multitasking. Updating a Progress bar is just about low cost enough to never really cause issues.
The default pattern is to only over write relevant amount of data after you got it all.
If you run into a exception or cancel, the pattern is to asume that all data is faulty and not have it on the UI.
I like to call the BackgroundWorker "Multitasking/-Threading Training Wheels". They teach you all those things. The firt part, by making the handing out akward. The second part, by actually throwing a Exception if you try to use the Result in invalid cases.
You propably retreive too much
Perhaps the most common mistake with DB's, is trying to retrieve a lot of data to then do processing or filtering in the Client. A common mistake, so avoid it.
There is a limit to how much data a User can process whatever you would define as 1 page. Never more then 100 Data Fields at once is my advice. If you got do Filtering, Pagination or the sort, always do it in the Query. Moving this stuff to the client moves a lot of unesessary data over the Network to then be slower at processing/Filtering then the DB would ever have been.
Example code
This actually is my first BGW Project. I updated it a bit over the years, but the bulk of it is still valid:
#region Primenumbers
private void btnPrimStart_Click(object sender, EventArgs e)
{
if (!bgwPrim.IsBusy)
{
//Prepare ProgressBar and Textbox
int temp = (int)nudPrim.Value;
pgbPrim.Maximum = temp;
tbPrim.Text = "";
//Start processing
bgwPrim.RunWorkerAsync(temp);
}
}
private void btnPrimCancel_Click(object sender, EventArgs e)
{
if (bgwPrim.IsBusy)
{
bgwPrim.CancelAsync();
}
}
private void bgwPrim_DoWork(object sender, DoWorkEventArgs e)
{
int highestToCheck = (int)e.Argument;
//Get a reference to the BackgroundWorker running this code
//for Progress Updates and Cancelation checking
BackgroundWorker thisWorker = (BackgroundWorker)sender;
//Create the list that stores the results and is returned by DoWork
List<int> Primes = new List<int>();
//Check all uneven numbers between 1 and whatever the user choose as upper limit
for(int PrimeCandidate=1; PrimeCandidate < highestToCheck; PrimeCandidate+=2)
{
//Report progress
thisWorker.ReportProgress(PrimeCandidate);
bool isNoPrime = false;
//Check if the Cancelation was requested during the last loop
if (thisWorker.CancellationPending)
{
//Tell the Backgroundworker you are canceling and exit the for-loop
e.Cancel = true;
break;
}
//Determin if this is a Prime Number
for (int j = 3; j < PrimeCandidate && !isNoPrime; j += 2)
{
if (PrimeCandidate % j == 0)
isNoPrime = true;
}
if (!isNoPrime)
Primes.Add(PrimeCandidate);
}
//Tell the progress bar you are finished
thisWorker.ReportProgress(highestToCheck);
//Save Return Value
e.Result = Primes.ToArray();
}
private void bgwPrim_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
pgbPrim.Value = e.ProgressPercentage;
}
private void bgwPrim_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
pgbPrim.Value = pgbPrim.Maximum;
this.Refresh();
if (!e.Cancelled && e.Error == null)
{
//Show the Result
int[] Primes = (int[])e.Result;
StringBuilder sbOutput = new StringBuilder();
foreach (int Prim in Primes)
{
sbOutput.Append(Prim.ToString() + Environment.NewLine);
}
tbPrim.Text = sbOutput.ToString();
}
else
{
tbPrim.Text = "Operation canceled by user or Exception";
}
}
#endregion
In my C# windows form, I want to set notification label with loop and thread before fill the data into data grid view . for that I try to use below method and thread.
My Thread is
public void Run()
{
System.Windows.Forms.MessageBox.Show("this is System Thread");
m = new Dashboard();
string text = "";
Int32 a = 0;
do
{
Thread.Sleep(1000);
notiCount++;
/*Notifications ne = new Notifications(m.loadNotification);
ne.Invoke(text);*/
//Thread.Sleep(1000);
}
while (notiCount <= 10) ;
}
My method is
private void loadINtransfer(string status)
{
Int32 x = 0;
string text="";
SystemThreadings s = new SystemThreadings();
Thread t = new Thread(s.Run);
t.Start();
Thread.Sleep(100);
do
{
if (s.notiCount == 0)
{
text = "Request Data";
Thread.Sleep(1000);
this.loadNotification(text);
// MessageBox.Show("request");
}
else if (s.notiCount == 3)
{
text = "Fetching Data";
Thread.Sleep(1000);
//MessageBox.Show("request");
this.loadNotification(text);
}
else if (s.notiCount == 6)
{
text = "Loading Data";
Thread.Sleep(1000);
this.loadNotification(text);
//MessageBox.Show("loading");
}
else if (s.notiCount == 9)
{
text = "Done";
Thread.Sleep(1000);
this.loadNotification(text);
//MessageBox.Show("done");
}
//Thread.Sleep(200);
}
while (s.notiCount != 10);
//Thread.Sleep(5000);
MessageBox.Show("attach");
dt = dl.loadTransfer(status);
dgvDashboard.AutoGenerateColumns = false;
dgvDashboard.DataSource = dt;
}
but it only show Done part. other if parts are passing but not show. And I want to wait some time the all parts before load data to grid view. how can I do this. Please help Me.
As I alluded to in the comments, this is pretty well a poster-child use case for BackgroundWorker. I created a new Windows Forms application, added a button and a label (I didn't bother to rename them), and then double-clicked the button to add an event handler. After adding the BackgroundWorker code, this is what Form1.cs ended up looking like:
using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var bw = new BackgroundWorker();
bw.DoWork += Bw_DoWork;
bw.WorkerReportsProgress = true;
bw.ProgressChanged += Bw_ProgressChanged;
bw.RunWorkerCompleted += Bw_RunWorkerCompleted;
bw.RunWorkerAsync();
}
private void Bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("attach");
//dt = dl.loadTransfer(status);
//dgvDashboard.AutoGenerateColumns = false;
//dgvDashboard.DataSource = dt;
}
private void Bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (e.ProgressPercentage == 0)
{
label1.Text = "Request Data";
}
else if (e.ProgressPercentage == 3)
{
label1.Text = "Fetching Data";
}
else if (e.ProgressPercentage == 6)
{
label1.Text = "Loading Data";
}
else if (e.ProgressPercentage == 9)
{
label1.Text = "Done";
}
}
private void Bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
int notiCount = 0;
do
{
Thread.Sleep(1000);
notiCount++;
worker.ReportProgress(notiCount);
}
while (notiCount <= 10);
}
}
}
Notice that we're not having to sleep or wait on the UI thread. When progress has been made, we're notified and can access the UI to update it. And when the work is complete, we again get notified.
The only Thread.Sleep we have is within the background worker, and I assume there is standing for actual useful work being done.
You absolutely should not have any Thread.Sleep calls in any constrained context such as the UI thread, where there aren't likely to be any other threads available to service other uses which may want to use your thread whilst you're just blocking it. Even Sleeping a threadpool thread is acting as a bad "team player" in modern multi-threaded applications.
So I can't say for sure this is the issue but I'm just about positive it is. I have a recordset of IVR calls to make. I put the data for each one in a concurrent queue and start 5 background workers to start working from the queue. However, after making 2 calls, the calls stop coming until one person hangs up, then it moves on to call number 3,4,5 etc. Are the any issues with this code?
It seems like the background workers are blocking eachother from calling the same method...? Is that possible?
private ConcurrentQueue<DataTable> _ivrCallsQueue = new ConcurrentQueue<DataTable>();
private List<BackgroundWorker> _ivrCallers = new List<BackgroundWorker>();
public overrid void Process()
{
foreach(DataRow row in _tblRecordsToProcess.Rows)
{
_workingActionItem = actionItemDAL.GetActionItemFromId(Convert.ToInt32(row["FNActionItemId"].ToString()));
var workingActionItemsTable = actionItemDAL.GetActionItemParamValues(Convert.ToInt32(row["FNActionItemId"].ToString()));
ivrCallsQueue.Enqueue(workingActionItemsTable);
}
StartCalls();
while (_ivrCallers.Count != 0)
{
testurls = testurls;
}
}
private void StartCalls()
{
int maxLines = 5;
if (_ivrCallsQueue.Count < maxLines)
{
maxLines = _ivrCallsQueue.Count;
}
for (int i = 0; i < maxLines; i++)
{
DataTable workingCall = new DataTable();
_ivrCallsQueue.TryDequeue(out workingCall);
BackgroundWorker ivrCaller = new BackgroundWorker();
_ivrCallers.Add(ivrCaller);
ivrCaller.DoWork += delegate(object sender, DoWorkEventArgs e)
{
RequestIVR(workingCall, Convert.ToInt32(workingCall.Rows[2][0].ToString()));
_ivrCallers.Remove(ivrCaller);
};
ivrCaller.RunWorkerCompleted += (bw_AnalyzeResults);
ivrCaller.RunWorkerAsync();
}
}
private void bw_AnalyzeResults(object sender, RunWorkerCompletedEventArgs e)
{
DataTable workingCall = new DataTable();
if (_ivrCallsQueue.Count != 0)
{
_ivrCallsQueue.TryDequeue(out workingCall);
BackgroundWorker ivrCaller = new BackgroundWorker();
ivrCaller.DoWork += delegate(object completeSender, DoWorkEventArgs completeArgs)
{
RequestIVR(workingCall, Convert.ToInt32(workingCall.Rows[2][0].ToString()));
_ivrCallers.Remove(ivrCaller);
};
ivrCaller.RunWorkerCompleted += (bw_AnalyzeResults);
ivrCaller.RunWorkerAsync();
}
else
{
}
}
private void RequestIVR(DataTable workingTable,int fnActionItemID)
{
var urlRequest = "http://uccx_http_trigger:9080/test?strTestMode=1&strTaskID=" + fnActionItemID;
var webClient = new WebClient { UseDefaultCredentials = true, Proxy = WebRequest.DefaultWebProxy };
DecodeResponseType(GetValueFromElement("Response Code was ", webClient.DownloadString(urlRequest)));
}
This will spawn at most five threads that each attempt to pull the next item from the queue and process it. If the queue is empty the attempt will fail and the thread will simply exit:
private List<System.Threading.Thread> Threads = new List<System.Threading.Thread>();
private ConcurrentQueue<DataTable> _ivrCallsQueue = new ConcurrentQueue<DataTable>();
private void StartCalls()
{
int maxLines = Math.Min(5 , _ivrCallsQueue.Count);
for (int i = 0; i < maxLines; i++ )
{
System.Threading.Thread T = new System.Threading.Thread(delegate()
{
DataTable workingCall;
while (_ivrCallsQueue.TryDequeue(out workingCall))
{
RequestIVR(workingCall, Convert.ToInt32(workingCall.Rows[2][0].ToString()));
}
});
Threads.Add(T);
T.Start();
}
}
The threads will keep running until all the items have been processed.
It looks like bw_AnalyzeResults does pretty much the same thing that StartCalls() does. In other words, when the background worker has finished its work, you immediately enqueue the same work to happen again, recursively forever?
By the looks of it, you want bw_AnalyzeResults to analyze the results returned by calling your web service. That is not what is happening at the moment.
The code below taken from the bw_AnalyzeResults event handler is scheduling a background job and making itself handle the RunWorkerCompleted event. So, presumably the software keeps going around and around executing bw_AnalyzeResults forever until you kill the process?
private void bw_AnalyzeResults(object sender, RunWorkerCompletedEventArgs e)
{
ivrCaller.DoWork += delegate(object completeSender, DoWorkEventArgs completeArgs)
{
RequestIVR(workingCall, Convert.ToInt32(workingCall.Rows[2][0].ToString()));
_ivrCallers.Remove(ivrCaller);
};
ivrCaller.RunWorkerCompleted += (bw_AnalyzeResults);
}
I am getting a ContextSwitchDeadlock when I try to add a large amount of graphics to a map. I would love to use the BackgroundWorker Class especially since I have never had the opportunity, but I am not sure how to in this situation.
C#:
private void AttributeSearchButton_Click(object sender, RoutedEventArgs e)
{
BackgroundWorker bw = new BackgroundWorker();
bw.WorkerReportsProgress = true;
bw.WorkerSupportsCancellation = true;
bw.DoWork += new DoWorkEventHandler(RunQuery);
bw.ProgressChanged += new ProgressChangedEventHandler(ProgressChanged);
}
private void RunQuery(object sender, DoWorkEventArgs e)
{
_attributeQueryGraphicsLayer.Graphics.Clear();
QueryTask queryTask = new QueryTask("http://xx.x.x.xxx:6080/arcgis/rest/services/Calvert_City_Test/MapServer/2");
queryTask.ExecuteCompleted += GeneralQueryTask_ExecuteCompleted;
queryTask.Failed += GeneralQueryTask_Failed;
var dirty = DateTime.UtcNow;
Query query = new Query();
query.OutFields.Add("*");
query.ReturnGeometry = true;
query.Where = "CIS_METR LIKE '%" + QueryParametersTextbox.Text + "%' OR COMMENTS LIKE '%" + QueryParametersTextbox.Text + "%'";
query.OutSpatialReference = MyMap.SpatialReference;
queryTask.ExecuteAsync(query);
}
// Draw results when query is complete
private void GeneralQueryTask_ExecuteCompleted(object sender, ESRI.ArcGIS.Client.Tasks.QueryEventArgs args)
{
// Clear previous results
QueryDataGrid.Visibility = Visibility.Visible;
GraphicsLayer graphicsLayer = MyMap.Layers["QueryResults"] as GraphicsLayer;
graphicsLayer.ClearGraphics();
// Check for new results
FeatureSet featureSet = args.FeatureSet;
bool isExceedTransferLimit = args.ExceededTransferLimit;
try
{
if (featureSet.Features.Count > 0 && isExceedTransferLimit == false)
{
// Add results to map
foreach (Graphic resultFeature in featureSet.Features)
{
//resultFeature.Symbol = ResultsFillSymbol;
graphicsLayer.Graphics.Add(resultFeature);
}
}
else
{
MessageBox.Show("No features found");
}
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}
// Notify when query fails
private void GeneralQueryTask_Failed(object sender, TaskFailedEventArgs args)
{
MessageBox.Show("Query failed: " + args.Error);
}
private void ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.ProgressTextbox.Content = (e.ProgressPercentage.ToString() + "%");
}
I know that the logic is off in this, but I am clueless on how to fix it. I have referred to http://msdn.microsoft.com/en-us/library/System.ComponentModel.BackgroundWorker(v=vs.95).aspx for help with how to use the class, however the information provided is not for this specific situation.
What I am wanting to do:
When the user clicks the Search button, it will Run the query. This works perfectly. The problem is when it runs the GeneralQueryTask_ExecuteCompleted I get a ContextSwitchDeadlock message if there are a large amount of records. This also leaves the UI unresponsive.
From what I have read I would need to put:
if (worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
where the time consuming task takes place. The problem is that there is no overloaded method for me to be able to do the QueryTask and the BackgroundWorker. Any help would be appreciated. If you need more information, please let me know.
Here i'm using multiple backgroundworkers to do one network related operation.Basically its a process of checking the user is registered with my page or not. I'm having nearly 1000 accounts to check, hence i'm using datagridview to import users and fetch the username from same for checking purpose. My code working fine and displays the result, But the problem is when updating the status in datagridview its not that much effective. In that long process method i used to set status text for every process of method, like login process started logged in failed to login .But Backgroundworker does not updating the status column. It displaying the status after all backgroundworker completes only. Can anyone give me an idea for how to update the status for each account ??
thanks in advance
It my code:
int threadNum;
public BackgroundWorker bcheker;
private void toolStripButton2_Click(object sender, EventArgs e)
{
if (wbcheckStatus == WorkerStatus.NotStarted || wblogcheckStatus == WorkerStatus.Completed)
{
threadNum = -1;
SetControlsStatus(ProgramStatus.BChecking);
toolStripButton2.Image = aTumblr.Properties.Resources.control_stop;
for (int i = 0; i < 4; i++)
{
bcheker = new BackgroundWorker();
bcheker.DoWork += new DoWorkEventHandler(bcheker_dowork);
bcheker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bchecker_completed);
bcheker.ProgressChanged +=bcheker_ProgressChanged;
bcheker.WorkerReportsProgress = true;
bcheker.WorkerSupportsCancellation = true;
bcheker.RunWorkerAsync();
}
}
else
{
threadNum = 10000;
bcheker.CancelAsync();
SetControlsStatus(ProgramStatus.BlogChecking);
}
}
public void bcheker_dowork(object sender, DoWorkEventArgs e)
{
while (!bcheker.CancellationPending)
{
int rownum = Interlocked.Increment(ref threadNum);
if (rownum >= bchecktableModel.Rows.Count)
{
break;
}
Thread.Sleep(1000);
BlogChecker bc = new BlogChecker(bchecktableModel[rownum, 1].Text, bchecktableModel[rownum, 2]);
bc.check();
wblogcheckStatus = WorkerStatus.Running;
}
if (bcheker.CancellationPending)
{
wblogcheckStatus = WorkerStatus.Completed;
SetControlsStatus(ProgramStatus.BCheckingDone);
}
}
public void bcheker_ProgressChanged(Object sender, ProgressChangedEventArgs e)
{
}
public void bchecker_completed(object sender, EventArgs e)
{
if (threadNum == bchecktableModel.Rows.Count+1)
{
SetControlsStatus(ProgramStatus.BCheckingDone);
wblogcheckStatus = WorkerStatus.Completed;
}
}
First of all, It looks like you have an issue of multiple handlers registering to the DoWorkEvent.
I am not sure what is happening, but I would check How many time the bcheker_dowork method is being called.
In order to report about your progress, use the BackgroundWorker.ReportProgress method.
public void bcheker_ProgressChanged(Object sender, ProgressChangedEventArgs e)
{
//Update your progress here
}
Also, in your DoWork() method, you shouldn't be using "bcheker" as that will simply refer to the last BackgroundWorker created. Instead, cast the sender parameter to a local BackgroundWorker variable and use that.