![](/img/trans.png)
[英]Passing argument into backgroundWorker (for use as a Cancel button)
[英]Passing argument to Backgroundworker error handler
我的程序必須同時在不同的插槽中測試幾種產品。 如果在插槽中出現錯誤(例如意外從計算機上卸下),則該程序應將用戶啟動UI時提供的錯誤類型和產品序列號記錄到文本文件中。
我正在使用Background Worker來處理多線程。 雖然我設法使用e.Error記錄了錯誤類型,但似乎無法弄清楚如何將序列號從DoWork函數傳遞給Background Worker錯誤處理程序。
我嘗試使用谷歌搜索解決方案,但似乎以前沒人問過。 我將非常感謝您提供的任何幫助。 PS:我對C#還是很陌生,所以要小心哈哈:)
下面是一個示例代碼:
private void startAsync_Click(object sender, EventArgs e)
{
if (backgroundWorker1.IsBusy != true)
{
// Start the asynchronous operation.
backgroundWorker1.RunWorkerAsync();
}
}
private void cancelAsync_Click(object sender, EventArgs e)
{
if (backgroundWorker1.WorkerSupportsCancellation == true)
{
// Cancel the asynchronous operation.
backgroundWorker1.CancelAsync();
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
int b = 0; //simulate error
for (int i = 1; i <= 10; i++)
{
if (worker.CancellationPending == true)
{
string[] array2 = { "1", "cancelled" };
e.Result = array2; //passing values when user cancel through e.Result object
e.Cancel = true;
break;
}
else
{
// Perform a time consuming operation and report progress.
worker.ReportProgress(i * 10, "Test a");
int a = 1 / b; //simulate error
System.Threading.Thread.Sleep(1000);
}
string[] array1 = {"1","done"};
e.Result = array1; //passing values when complete through e.Result object
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
resultLabel.Text = e.ProgressPercentage.ToString() + "%" + e.UserState.ToString();
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled == true)
{
string[] someArray2 = e.Result as string[];
string sernum = someArray2[0];
string status = someArray2[1];
resultLabel.Text = sernum + " " + status;
}
else if (e.Error != null)
{
resultLabel.Text = "Error: " + e.Error.Message; //how to pass sernum here?
}
else
{
string[] someArray = e.Result as string[];
string sernum = someArray[0];
string status = someArray[1];
resultLabel.Text = sernum + " " + status;
}
}
請參見下面的代碼。 你不需要上課。 可以使用類似的代碼簡單地發送字符串或整數。
public class Parameters
{
public string message = "";
}
private void startAsync_Click(object sender, EventArgs e)
{
if (backgroundWorker1.IsBusy != true)
{
// Start the asynchronous operation.
Parameters parameters = new Parameters() { message = "The quick brown fox jumped over the lazy dog" };
backgroundWorker1.RunWorkerAsync(parameters);
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
Parameters parameters = e.Argument as Parameters;
}
在發生異常的情況下,有很多不同的方法可以將數據返回到RunWorkerCompleted
事件處理程序。
恕我直言,從語義的角度來看,最自然的是將數據放入異常本身。 例如:
class BackgroundWorkerException : Exception
{
public string Sernum { get; }
public BackgroundWorkerException(string sernum, Exception inner)
: base("DoWork event handler threw an exception", inner)
{
Sernum = sernum;
}
}
然后在您的DoWork
處理程序中:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
try
{
int b = 0; //simulate error
for (int i = 1; i <= 10; i++)
{
if (worker.CancellationPending == true)
{
string[] array2 = { "1", "cancelled" };
e.Result = array2; //passing values when user cancel through e.Result object
e.Cancel = true;
break;
}
else
{
// Perform a time consuming operation and report progress.
worker.ReportProgress(i * 10, "Test a");
int a = 1 / b; //simulate error
System.Threading.Thread.Sleep(1000);
}
string[] array1 = {"1","done"};
e.Result = array1; //passing values when complete through e.Result object
}
}
catch (Exception e)
{
throw new BackgroundWorkerException("1", e);
}
}
最后,在RunWorkerCompleted
事件處理程序中:
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled == true)
{
string[] someArray2 = e.Result as string[];
string sernum = someArray2[0];
string status = someArray2[1];
resultLabel.Text = sernum + " " + status;
}
else if (e.Error != null)
{
string sernum = ((BackgroundWorkerException)e.Error).Sernum;
resultLabel.Text = "Error: " + e.Error.Message;
}
else
{
string[] someArray = e.Result as string[];
string sernum = someArray[0];
string status = someArray[1];
resultLabel.Text = sernum + " " + status;
}
}
您的問題不清楚sernum
實際代表什么,尤其是對於給定的后台任務而言,它是單個值,還是對於sernum
,單個任務可能具有多個值。 如果是前者,即您知道啟動任務時的值,則可以通過在每個實際事件處理程序使用的匿名方法中捕獲它,將其直接傳遞給事件處理程序。
如果不進行一些更改,該方法將無法在您的特定情況下起作用。 您似乎已將單個BackgroundWorker
對象作為組件添加到窗體中,並且正在重用它。 如果您每次都創建一個新的BackgroundWorker
,則使用匿名方法會更好/更容易地工作,以便您可以將匿名方法委托訂閱到DoWork
和RunWorkerCompleted
。 (您必須在每次調用之前就訂閱它,因為大概每次的sernum
值都不同。)
您可以在此處執行此操作,使其與添加到設計器中表單中的單個組件一起工作,但是它要復雜得多,因為您必須向RunWorkerCompleted
事件動態添加處理程序,該處理程序同時取消訂閱自身和委托訂閱了DoWork
和RunWorkerCompleted
事件(在此方案中,您不會直接將任何方法訂閱給Designer中的組件)。
另一種選擇是創建一個自定義數據結構作為RunWorkerAsync()
的參數傳遞,該結構可以包含sernum
值的屬性。 您可以在啟動工作程序的方法或DoWork
事件處理程序中設置此值。
這種方法僅適合您所擁有的“設計器中的組件”方案,因為您仍然需要一種將對自定義數據結構的引用返回給RunWorkerCompleted
事件處理程序的方法,您只能將其存儲在例如一個可以在啟動工作程序的Click
事件處理程序和RunWorkerCompleted
事件之間共享的實例字段(坦率地說,如果您這樣做,那么在那個時候是否值得將該引用傳遞給RunWorkerAsync()
方法是否值得爭論,因為DoWork
事件處理程序也可以到達相同的實例字段。)
另一種選擇是捕獲異常,就像我在上面的代碼示例中所做的那樣,但是不要重新拋出異常,而應將其視為已取消工作(即,設置Result
和Cancel
屬性)。
另一種方法是完全放棄BackgroundWorker
並切換到基於TPL Task
的習慣用法。 但這並不能隱式解決問題,但是可以使用上述任何選項,也可以只定義自己的錯誤回傳模式。
如果您需要的不是其他特定幫助,則需要發布一個新問題,並提供一個良好的“ 最小,完整和可驗證”代碼示例 ,該示例顯示了您嘗試過的上述方法之一,或未列出的其他替代方法在這里,以及您無法弄清楚的具體內容。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.