1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
| #region Références
using System;
using System.ComponentModel;
using System.Threading;
#endregion
/// <summary>
/// Représente un BackgroundWorker qui fonctionne dans un thread STA.
/// </summary>
public class STABackgroundWorker
: Component
{
#region Evènements
/// <summary>
/// Cet evènement se produit lorsque le thread d'arrière plan démarre, placez votre code de traitement ici.
/// Handler exécuté dans le thread d'arrière plan.
/// </summary>
public event DoWorkEventHandler DoWork;
/// <summary>
/// Cet évènement se produit lorsque le thread d'arrière plan notifie de sa progression.
/// Handler exécuté dans le thread d'interface graphique.
/// </summary>
public event ProgressChangedEventHandler ProgressChanged;
/// <summary>
/// Cet évènement se produit lorsque le thread d'arrière plan est terminé.
/// Handler exécuté dans le thread d'arrière plan
/// </summary>
public event RunWorkerCompletedEventHandler RunWorkerCompleted;
#endregion
#region Variables
private bool _IsRunning;
private bool _CanCancel;
private bool _ReportProgress;
private int _Progress;
private Thread _Thread;
private SynchronizationContext _SyncContext;
#endregion
#region Propriétés
/// <summary>
/// Obtient une valeur indiquant si le thread est en cours d'exécution ou non.
/// </summary>
public bool IsBusy
{
get { return _IsRunning; }
}
/// <summary>
/// Obtient ou définit une valeur indiquant si le thread notifie de l'avancement.
/// </summary>
public bool WorkerReportsProgress
{
get { return _ReportProgress; }
set { _ReportProgress = value; }
}
/// <summary>
/// Obtient ou définit une valeur indiquant si le thread supporte l'annulation.
/// </summary>
public bool WorkerSupportsCancellation
{
get { return _CanCancel; }
set { _CanCancel = value; }
}
#endregion
#region Constructeur
/// <summary>
/// Construit un STABackgroundWorker.
/// </summary>
public STABackgroundWorker()
{
Reset();
_CanCancel = true;
_ReportProgress = true;
_SyncContext = SynchronizationContext.Current ?? new SynchronizationContext();
}
#endregion
#region Méthodes
/// <summary>
/// Ré-initialise les variables locales.
/// </summary>
private void Reset()
{
_IsRunning = false;
_Progress = 0;
_Thread = null;
}
/// <summary>
/// Démarre le traitement.
/// </summary>
public void RunWorkerAsync()
{
RunWorkerAsync(null);
}
/// <summary>
/// Démarre le traitement.
/// </summary>
/// <param name="argument">Argument passé au traitement</param>
public void RunWorkerAsync(object argument)
{
if (_IsRunning) throw new InvalidOperationException("Le BackgroundWorker est déjà en cours d'exécution.");
Reset();
_Thread = new Thread(ThreadStart);
_Thread.SetApartmentState(ApartmentState.STA);
_Thread.Start();
}
/// <summary>
/// Point d'entré du thread.
/// </summary>
/// <param name="argument">Argument du thread.</param>
private void ThreadStart(object argument)
{
bool cancelled = false;
Exception error = null;
DoWorkEventArgs e = new DoWorkEventArgs(argument);
try
{
if(DoWork != null) DoWork(this, e);
}
catch(ThreadAbortException)
{
cancelled = true;
}
catch (Exception ex)
{
error = ex;
}
_SyncContext.Send(ThreadCompleted, new Tuple<Object, Exception, bool>(e.Result, error, cancelled || e.Cancel));
}
/// <summary>
/// Cette méthode est appelée lorsque le thread est terminé.
/// </summary>
/// <param name="result">Objet résultat du traitement.</param>
/// <param name="error">Erreur éventuelle. <c>null</c> si pas d'erreur.</param>
/// <param name="cancel">Indique si le thread à été annulé ou non.</param>
private void ThreadCompleted(object args)
{
if (RunWorkerCompleted != null)
{
Tuple<object, Exception, bool> r = args as Tuple<object, Exception, bool>;
RunWorkerCompletedEventArgs e = new RunWorkerCompletedEventArgs(r.Item1, r.Item2, r.Item3);
RunWorkerCompleted(this, e);
}
}
/// <summary>
/// Annule le traitement en cours.
/// </summary>
public void CancelAsync()
{
if(!_CanCancel) throw new InvalidOperationException("Ce traitement ne supporte pas l'annulation.");
if (_Thread != null && _IsRunning) _Thread.Abort();
}
/// <summary>
/// Délégué pour rapporter la progression.
/// </summary>
/// <param name="args">Argument de l'évènement.</param>
private void OnProgressChanged(object args)
{
if (ProgressChanged != null)
ProgressChanged(this, args as ProgressChangedEventArgs);
}
/// <summary>
/// Notifier de la progession.
/// </summary>
/// <param name="percentProgress">Pourcentage de progression.</param>
public void ReportProgress(int percentProgress)
{
ReportProgress(percentProgress, null);
}
/// <summary>
/// Notifier de la pogression.
/// </summary>
/// <param name="percentProgress">Pourcentage de progression.</param>
/// <param name="userState">Objet utilisateur.</param>
public void ReportProgress(int percentProgress, object userState)
{
if (!WorkerReportsProgress)
throw new InvalidOperationException("Ce BackgroundWorker ne permet pas de notifier de la progression.");
_Progress = percentProgress;
if (ProgressChanged != null)
{
ProgressChangedEventArgs e = new ProgressChangedEventArgs(_Progress, userState);
_SyncContext.Send(OnProgressChanged, e);
}
}
#endregion
} |
Partager