2010-01-13 29 views
2

我有一個.net WinForms應用程序。我有一個基於用戶操作實例化的UserControl - 在實例化時,它在後臺線程(使用BackgroundWorker)上執行一些耗時的任務,同時顯示ajaxy旋轉動畫。用戶可以隨時點擊,然後點擊回到用戶控件(這將重新啓動後臺線程)。什麼是在WinForms應用程序中殺死後臺任務的模式

當用戶點擊時,我想要處置UserControl及其擁有的所有資源(包括後臺線程)。這樣做的最好方法是什麼?

+0

那麼你是說當表單失去焦點時,你想要處理它嗎? – ChaosPandion 2010-01-13 17:59:41

+0

@Chaos,當表單失去焦點時。該應用程序具有Outlook風格的界面。切換到側邊欄中的其他項目時,這是我想要處置的時間。 – AngryHacker 2010-01-13 19:16:54

回答

1

調用BackgroundWorker上的CancelAsync方法並等待它終止。構建您的工人代碼,以便它經常檢查取消標誌。

如果線程繼續運行一段時間沒有負面影響,並且它不會引用用戶控件或它所持有的任何資源,則可以在請求線程到達後處理用戶控件終止。

編輯:演示代碼

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 

namespace WindowsFormsApplication1 
{ 
    public partial class FrmMain : Form 
    { 
     public FrmMain() 
     { 
      InitializeComponent(); 
     } 

     private void bg_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
     { 
      MessageBox.Show("BG Done"); 
     } 

     private void btnStart_Click(object sender, EventArgs e) 
     { 
      bg.WorkerSupportsCancellation = true; 
      bg.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bg_RunWorkerCompleted); 
      bg.DoWork += new DoWorkEventHandler(bg_DoWork); 
      bg.RunWorkerAsync(); 
     } 

     void bg_DoWork(object sender, DoWorkEventArgs e) 
     { 
      int i=0; 

      while (!bg.CancellationPending) 
      { 
       lblStatus.BeginInvoke((MethodInvoker) delegate { lblStatus.Text = i + " sec."; }); 
       System.Threading.Thread.Sleep(1000); 
       i++; 
      } 

      lblStatus.BeginInvoke((MethodInvoker)delegate { lblStatus.Text = "CANCEL"; }); 
     } 

     private void btnStop_Click(object sender, EventArgs e) 
     { 
      bg.CancelAsync(); 
      while (bg.IsBusy) // For real code limit max wait time in while loop 
      { 
       System.Threading.Thread.Sleep(50); 
       Application.DoEvents(); 
      } 
      this.Close(); 
     } 
    } 
} 


namespace WindowsFormsApplication1 
{ 
    partial class FrmMain 
    { 
     /// <summary> 
     /// Required designer variable. 
     /// </summary> 
     private System.ComponentModel.IContainer components; 

     /// <summary> 
     /// Clean up any resources being used. 
     /// </summary> 
     /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> 
     protected override void Dispose(bool disposing) 
     { 
      if (disposing && (components != null)) 
      { 
       components.Dispose(); 
      } 
      base.Dispose(disposing); 
     } 

     #region Windows Form Designer generated code 

     /// <summary> 
     /// Required method for Designer support - do not modify 
     /// the contents of this method with the code editor. 
     /// </summary> 
     private void InitializeComponent() 
     { 
      this.bg = new System.ComponentModel.BackgroundWorker(); 
      this.btnStart = new System.Windows.Forms.Button(); 
      this.btnStop = new System.Windows.Forms.Button(); 
      this.lblStatus = new System.Windows.Forms.Label(); 
      this.SuspendLayout(); 
      // 
      // bg 
      // 
      this.bg.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.bg_RunWorkerCompleted); 
      // 
      // btnStart 
      // 
      this.btnStart.Location = new System.Drawing.Point(39, 13); 
      this.btnStart.Name = "btnStart"; 
      this.btnStart.Size = new System.Drawing.Size(75, 23); 
      this.btnStart.TabIndex = 0; 
      this.btnStart.Text = "Start"; 
      this.btnStart.UseVisualStyleBackColor = true; 
      this.btnStart.Click += new System.EventHandler(this.btnStart_Click); 
      // 
      // btnStop 
      // 
      this.btnStop.Location = new System.Drawing.Point(39, 42); 
      this.btnStop.Name = "btnStop"; 
      this.btnStop.Size = new System.Drawing.Size(75, 23); 
      this.btnStop.TabIndex = 1; 
      this.btnStop.Text = "Stop"; 
      this.btnStop.UseVisualStyleBackColor = true; 
      this.btnStop.Click += new System.EventHandler(this.btnStop_Click); 
      // 
      // lblStatus 
      // 
      this.lblStatus.AutoSize = true; 
      this.lblStatus.Location = new System.Drawing.Point(39, 72); 
      this.lblStatus.Name = "lblStatus"; 
      this.lblStatus.Size = new System.Drawing.Size(73, 13); 
      this.lblStatus.TabIndex = 2; 
      this.lblStatus.Text = "(Not Running)"; 
      // 
      // FrmMain 
      // 
      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 
      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 
      this.ClientSize = new System.Drawing.Size(423, 136); 
      this.Controls.Add(this.lblStatus); 
      this.Controls.Add(this.btnStop); 
      this.Controls.Add(this.btnStart); 
      this.Name = "FrmMain"; 
      this.Text = "Main"; 
      this.ResumeLayout(false); 
      this.PerformLayout(); 

     } 

     #endregion 

     private System.ComponentModel.BackgroundWorker bg; 
     private System.Windows.Forms.Button btnStart; 
     private System.Windows.Forms.Button btnStop; 
     private System.Windows.Forms.Label lblStatus; 
    } 
} 
+0

不要等到它終止,當BGW有一個RunWorkerCompleted事件處理程序時,會死鎖。 – 2010-01-13 22:56:05

+0

不是,但您需要在等待時調用Application.DoEvents()。添加的代碼演示(VS 2010/.NET 4) – 2010-01-13 23:36:29

1

您可能需要掛接到Progress Changed Event。讓您的工作人員在可以安全地停止而不會丟失工作的情況下調用此事件。現在,您可以通過設置ProgressChangedEventArgs中的值來存儲任務的當前狀態,然後可以重新開始停止工作,而不會丟失工作。

+0

無法真正做到這一點,因爲UserControl擊中了一個基本上阻塞直到它返回結果的遠程服務。 – AngryHacker 2010-01-13 17:39:56

相關問題