Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Question
Wednesday, June 17, 2015 10:13 PM
Maybe creating a class with parameters ?
I have in Form1 this events:
private void videosInsertRequest_ResponseReceived(Video obj)
{
toolStripStatusLabel1.Text = obj.Status.UploadStatus;
}
private void videosInsertRequest_ProgressChanged(IUploadProgress obj)
{
toolStripStatusLabel1.Text = obj.Status.ToString();
}
And i want to pass both obj.Status.UploadState from the first event and obj.Status.ToString() from the second event to backgroundworker progresschanged event and there to assign each value to toolStripStatusLabel1 and toolStripStatusLabel2.
The problem is that reportprogress of backgroundworker can report one parameter. And accept only int.
If i will try to assign to the Labels this way i will get cross thread ecxeption.
In fact from the first event i want to report only the UploadStatus but in the second event i want to report also the Status.ToString() and also obj.BytesSent and BytesSend is type of long and i want to cast it to decimal the problem is reportprogress can get only int.
1. How to pass multiple arguments ?
2. How to pass the BytesSend as decimal and not int ?
All replies (4)
Thursday, June 18, 2015 6:14 AM âś…Answered
The userState is of type object so just pass in the string[], and use it directly.
private void videosInsertRequest_ResponseReceived(Video obj)
{
stringProgressReport[0] = obj.Status.UploadStatus;
backgroundWorker1.ReportProgress(0, stringProgressReport);
}
The ProcessChanged handler can stay as it is.
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
string[] labelsreports = (string[])e.UserState;
toolStripStatusLabel1.Text = labelsreports[0];
toolStripStatusLabel2.Text = labelsreports[1];
}
If you need a code sample to work with this one passes a SearchResult object as the userState.
Thursday, June 18, 2015 3:56 AM
What i tried now is adding a string array to the top of form1:
string[] stringProgressReport = new string[2];
Then inside the two events i did:
private void videosInsertRequest_ResponseReceived(Video obj)
{
string r1 = stringProgressReport[0] = obj.Status.UploadStatus;
backgroundWorker1.ReportProgress(0, r1);
}
static string progress = "";
static string ttt = "";
private void videosInsertRequest_ProgressChanged(IUploadProgress obj)
{
string r2 = stringProgressReport[1] = obj.Status.ToString();
backgroundWorker1.ReportProgress(0, r2);
}
And then in the backgroundworker progresschanged event i did:
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
string[] labelsreports = (string[])e.UserState;
toolStripStatusLabel1.Text = labelsreports[0];
toolStripStatusLabel2.Text = labelsreports[1];
}
But getting exception on (string[])e.UserState
Unable to cast object of type 'System.String' to type 'System.String[]'.
And i'm not sure if this is the right way at all to report multiple.
Thursday, June 18, 2015 4:13 AM | 1 vote
Never try to pass anything but value types or string from or to the BackgroundWorker. Or really any form of alternate thread. These are the only types that are inherently thread save.
For all the other types (inlcuding arrays of those types), only hand them in or out if you don't keep a reference around, or you cloned them properly to have a distinct instance. You don't want to have to deal with race conditions because 2 threads worked on the same data.
DoWork runs in the altnerate thread.
ProgressReport and Completed Events in turn are raised on the GUI thread. Only try to access the GUI in those.
Completed also will get the full result set (as assigned in the DoWork) and is generally the first place you should expect some results in. Don't try to pass partial results out of DoWork via Progress Report.
I made a example of how to use the BGW for brute-forcing all the primes in a range:
#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
One original design was actually to write every found Prime via Progress Report and write them right to the UI. However the event triggered so often it outright overloaded the GUI thread for several seconds, making the whole thing non-responsive again.
Thursday, June 18, 2015 7:14 AM | 1 vote
The backgroundworker is designed to make working with async easier for simple tasks. (For instance keeping the UI responsive).
That does not mean that you can do also complex async tasks with it.
If you want currently Async than take a look at the in C# build in keywords for that.
https://msdn.microsoft.com/en-us/library/hh491443.aspx?f=255&MSPPError=-2147217396
Success
Cor