[英].NET BackgroundWorker RunWorkerAsync() oddly gets called twice
[英]DoWork of BackgroundWorker is called twice when RunWorkerAsync is called once?
我已經在一個可以工作的類中創建了一個backgroundworker,但是如果我調用並等到結束運行,則第二次調用它,它將執行相同的過程兩次
我認為bw.DoWork有什么問題+ =
private void button1_Click(object sender, EventArgs e)
{
nptest.test.start("null", "null");
}
namespace nptest
{
class test
{
public static void start(string str, string strb)
{
if (bw.IsBusy != true)
{
bw.WorkerSupportsCancellation = true;
bw.DoWork += (obj, e) => bw_DoWork(str, strb);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
bw.RunWorkerAsync();
}
}
private static BackgroundWorker bw = new BackgroundWorker();
private static void bw_DoWork(string str, string strb)
{
System.Windows.Forms.MessageBox.Show("initializing BackgroundWorker");
}
private static void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if ((e.Cancelled == true))
{
Console.WriteLine("Canceled");
}
else if (!(e.Error == null))
{
Console.WriteLine("Error: " + e.Error.Message);
}
bw.Dispose();
}
}
}
問題解決了
class test
{
private static List<object> arguments = new List<object>();
// initializing with program startup
public static void bwinitializing()
{
bw.WorkerSupportsCancellation = true;
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
}
public static void start(string str, string strb)
{
if (bw.IsBusy != true)
{
arguments.Clear();
arguments.Add(str);
arguments.Add(strb);
bw.RunWorkerAsync(arguments);
}
}
private static BackgroundWorker bw = new BackgroundWorker();
private static void bw_DoWork(object sender, DoWorkEventArgs e)
{
List<object> genericlist = e.Argument as List<object>;
System.Windows.Forms.MessageBox.Show("BackgroundWorker " + genericlist[0]);
}
我懷疑會不小心添加了多個 DoWork
事件。
也就是說, 每次調用start
方法時,它都會注冊一個新的 DoWork
事件處理程序。 這將添加而不是替換現有的處理程序DoWork
處理程序。 因此,將有多個DoWork
處理程序被稱為后續時間DoWork
等。
// creates a NEW delegate and adds a NEW handler
bw.DoWork += (obj, e) => bw_DoWork(str, strb);
我建議不要在這里使用閉包,而應該使用方法組(將其隱式轉換為委托),然后將數據傳遞給RunWorkerAsync
調用(有一種接受數據參數的形式)。
RunWorkerCompleted +=
行沒有此問題,因為它從方法組傳遞了一個委托(保證始終評估為同一委托對象1 )。 因此,對該行重復的+=
調用將替換處理程序。
例:
class MyData {
public string StrA { get; set; }
}
// These only need to be setup once (and should be for clarity).
// However it will be "ok" now if they are called multiple times
// as, since the delegates are the same, the += will
// act as a replacement (as it replaces the previous delegate with itself).
bw.WorkerSupportsCancellation = true;
bw.DoWork += bw_DoWork;
bw.RunWorkerCompleted += bw_RunWorkerCompleted;
// Pass data via argument
bw.RunWorkerAsync(new MyData {
StrA = str,
});
void bw_DoWork (object sender, DoWorkEventArgs e) {
var data = (MyData)e.Argument;
var str = data.StrA;
// stuff
}
1我不確定是否可以保證等於引用相等,但是即使使用new DelegateType(MethodGroup)
獲得,使用此方法也可以從方法組的委托中穩定調用+=
和-=
。
Wrt。 我在主的評論:如果UI元素是從上他們沒有創建的線程訪問的話,會有好玩的“跨線程操作異常”。 我相信對消息框的這種使用是“可以的”(當不是使用所有者從另一個線程創建時),但是在BackgroundWorker的DoWork中訪問UI的做法通常是可疑的。
另外, 不要在這里調用bw.Dispose()
。 用擁有的容器或上下文處置它。 這似乎是很好的和良性的在這種情況下,但只做到這一點時BGW實例將永遠不會再使用。 從事件處理程序中調用它也是可疑的,因為BGW仍處於“活動”狀態。
我遇到了與以上評論員“ Power-Mosfet”相同的問題
最后,添加一個new BackgroundWorker()
然后分配給全局bw值將解決我的問題。
代碼是,從:
private BackgroundWorker gBgwDownload;
private void yourFunction_bw(xxx)
{
// Create a background thread
gBgwDownload.DoWork += bgwDownload_DoWork;
gBgwDownload.RunWorkerCompleted += bgwDownload_RunWorkerCompleted;
//omited some code
gBgwDownload.RunWorkerAsync(paraObj);
}
至:
private BackgroundWorker gBgwDownload;
private void yourFunction_bw(xxx)
{
// Create a background thread
gBgwDownload = new BackgroundWorker(); /* added this line will fix problem */
gBgwDownload.DoWork += bgwDownload_DoWork;
gBgwDownload.RunWorkerCompleted += bgwDownload_RunWorkerCompleted;
//omited some code
gBgwDownload.RunWorkerAsync(paraObj);
}
還有另一個原因。 在其生成的代碼中查找DoWorkEventHandler
InitializeComponent()
如果您是通過組件UI屬性生成的,並且還需要自己注冊。
因為如果再次注冊它,它將不會覆蓋前一個,但是會添加另一個事件,並且將調用兩次。
在我的情況下,BackgroundWorker運行了兩次,因為在我的窗體的構造函數類中,我聲明了DoWork,ProgressChanged和RunWorkerCompleted事件處理程序,但Visual Studio 2013已在此窗體類的Designer部分中聲明了它。
因此,我只是刪除了聲明,但效果很好。
謝謝...。這段代碼運行良好。為backroundworker創建新實例是個好主意。...現在,我們可以在for / while循環中調用此函數,並可以運行多個backgroundworker進程。
單擊按鈕后,我進行了這樣的編碼..而不影響主線程的流...多個進程將在背面運行....我只是使用消息框彈出了..但是我們可以做一些耗時的過程來在“ bgwDownload_DoWork“函數...,將創建多個進程...,而我們不需要檢查BackgroundWorker是否忙...
private void button1_Click(object sender, EventArgs e)
{
for (int i = 0; i < 3; i++)
yourFunction_bw(i);
}
private BackgroundWorker gBgwDownload;
private void yourFunction_bw(int i)
{
// Create a background thread
gBgwDownload = new BackgroundWorker(); // added this line will fix problem
gBgwDownload.DoWork += bgwDownload_DoWork;
gBgwDownload.RunWorkerAsync(i);
}
private void bgwDownload_DoWork(object sender, DoWorkEventArgs e)
{
int stre = (int)e.Argument;
MessageBox.Show(stre.ToString ()); // time taken process can be added here
}
我今天遇到了這個問題,當我注意到每次顯示表單時,都會多次調用后台工作程序RunWorkerCompleted事件,因此我將后台工作程序置於正在執行長時間運行任務的彈出窗體上。
我的問題是關閉表單后我沒有處理該表單,這意味着每次我顯示該表單時,都會在偶數中添加另一個處理程序。
處理完表格后解決了我的問題。 我想在我的情況下尋找解決方案時,只是想在這里提到它。
我從設計器中刪除了控件,並在代碼中實例化了一個新的WorkerProcess:
例如:var bwProcess = new BackgroundWorker();
bwProcess.DoWork + =新的DoWorkEventHandler(bwProcess_DoWork);
bwProcess.RunWorkerCompleted + = bwProcess_RunWorkerCompleted;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.