2010-01-13 12 views
2

J'ai reçu une application .net WinForms. J'ai un UserControl qui est instancié en fonction de l'action de l'utilisateur - lors de l'instanciation, il effectue des tâches fastidieuses sur un thread d'arrière-plan (en utilisant BackgroundWorker), tout en affichant l'animation de rotation ajaxy. L'utilisateur peut cliquer à tout moment, puis revenir sur le contrôle utilisateur (ce qui redémarre le thread d'arrière-plan).Quel est le modèle accepté de suppression des tâches d'arrière-plan dans une application WinForms?

Lorsque l'utilisateur clique, je souhaite disposer de UserControl et de toutes les ressources qu'il contient (y compris le thread d'arrière-plan). Quelle est la meilleure façon de faire cela?

+0

Donc, dites-vous que lorsque le formulaire perd le focus, vous voulez en disposer? – ChaosPandion

+0

@Chaos, pas quand le formulaire perd le focus. L'application dispose d'une interface de style Outlook. Lorsque vous passez à un autre élément dans la barre latérale, c'est à ce moment-là que je veux disposer. – AngryHacker

Répondre

1

Appelez la méthode CancelAsync sur BackgroundWorker et attendez qu'elle se termine. Construisez votre code de travail afin qu'il vérifie fréquemment l'indicateur d'annulation.

S'il n'y a pas d'effets secondaires négatifs si le thread continue à fonctionner pendant un certain temps, et qu'il ne référencera en aucun cas le contrôle utilisateur ou toute ressource qu'il contient, vous pouvez disposer du contrôle utilisateur après avoir demandé le thread à mettre fin.

EDIT: Code Démo

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

Ne l'attendez pas pour se terminer, cela bloquera lorsque le BGW a un gestionnaire d'événement RunWorkerCompleted. –

+0

Non vrai, mais vous devez appeler Application.DoEvents() en attendant. Code ajouté qui démontre (VS 2010/.NET 4) –

1

Vous pouvez accrocher dans le Progress Changed Event. Demandez à votre travailleur d'invoquer cet événement chaque fois qu'il peut être arrêté en toute sécurité sans perdre son travail. Maintenant, avec cela, vous pouvez stocker l'état actuel de la tâche en définissant la valeur ProgressChangedEventArgs, puis vous pouvez redémarrer où vous vous étiez arrêté sans perdre le travail.

+0

Ne peut pas vraiment faire cela parce que le contrôle UserControl frappe un service lointain qui bloque fondamentalement jusqu'à ce qu'il renvoie un résultat. – AngryHacker