2009-09-07 9 views
1

J'ai un UserControl avec quelque chose qui fonctionne en arrière-plan. Quand thing a un événement terminé, auquel le contrôle utilisateur est abonné. Depuis l'événement est soulevée dans un thread séparé et le gestionnaire d'événements ne une mise à jour du contrôle utilisateur je lance le gestionnaire d'événement avec ceci:C#: comment empêcher l'échec de l'appel

private void ProcessProcessCompleted(object sender, ProcessCompletedEventArgs e) 
{ 
    if (InvokeRequired) 
    { 
     Invoke(new Action<object, ProcessCompletedEventArgs>(ProcessProcessCompleted), 
      new[] { sender, e }); 
     return; 
    } 

    // Update the user control, etc. 
} 

Cela fonctionne bien, sauf si le formulaire qui contient le contrôle utilisateur est fermé avant que le processus ne soit terminé. J'ai essayé de vous désabonner à l'événement dans la méthode de disposition du contrôle de l'utilisateur, mais cela ne semble fonctionner que des parties du temps. Comment devrais-je faire ça? Je voudrais éviter de l'envelopper dans un bloc try catch. Y at-il une propriété InvokeIsPossible ou quelque chose que je peux vérifier avant d'invoquer?

Répondre

3

Vous pouvez utiliser le SynchronizationContext, il a été introduit dans le .NET 2 pour simplifier la communication inter-thread:

  • créer une variable globale SynchronizationContext (disons syncContext)
  • lsinitialisez au fil du formulaire sync'context:

    syncContext = SynchronizationContext.Current;

Changez votre méthode ProcessProcessCompleted comme ceci:

private void ProcessProcessCompleted(object sender, object e) 
{ 
    this.syncContext.Post(new SendOrPostCallback(delegate(object state) 
    { 
     // Update the user control, etc. 
    }) 
    , null);    
} 

Vous pouvez lire SynchronizationContext ici:

http://www.codeproject.com/KB/cpp/SyncContextTutorial.aspx

ou http://msdn.microsoft.com/en-us/library/system.threading.synchronizationcontext.aspx

+0

+1 pour relier au seul MSDN français. –

+0

J'étais excité, n'a pas fait attention, je vais le laisser pour justifier mon +1;) – manji

+0

version anglaise ici: http://msdn.microsoft.com/fr-fr/library/system.threading.synchronizationcontext.aspx –

1

Bien qu'il ne synchronise pas les fils, vous pouvez utiliser Control.IsDisposed pour vérifier si la méthode Invoke() peut être appelée dans l'état actuel (Form hérite de Control):

if (!this.IsDisposed) 
{ 
    // tatata... 
} 

Pour garantir c'est des travaux, vous devez l'envelopper dans un bloc lock(syncobject) { ... } pour vérifier un drapeau booléen personnalisé et changer également le drapeau dans un lock -Déclaration l'intérieur d'un événement Form_Close.

+0

+1. J'ai utilisé cette technique dans le passé et cela fonctionne. –

+0

J'ai essayé ceci, et parfois il a échoué toujours. Aucune idée pourquoi ... – Svish

+0

Avez-vous vérifié l'état de 'IsDisposed' dans le débogueur quand il a échoué? –

1

J'utilise une classe que j'appelle un thread-gate dont j'hérite habituellement mais vous pouvez juste l'instancier ou quoi que ce soit. Cela utilise la classe SynchronizationContext.

public class ThreadGate 
{ 
    private readonly SynchronizationContext _synchronizationContext; 
public ThreadGate() 
    { 
     _synchronizationContext = AsyncOperationManager.SynchronizationContext; 
    } 

    public void Post<T>(Action<T> raiseEventMethod, T e) 
    { 
     if (_synchronizationContext == null) 
      ThreadPool.QueueUserWorkItem(delegate { raiseEventMethod(e); }); 
     else 
      _synchronizationContext.Post(delegate { raiseEventMethod(e); }, null); 
    } 
} 

Je l'utilise comme ceci:

Post(OnProgressChanged,new ProgressChangedEventArgs(1,null))); 

Ou si vous aimez l'action

Action<string> callback; 
Post(callback,str)); 
+0

Solution intéressante. Est-ce ThreadGate utilisé dans le gui, ou par la classe qui fait le travail en arrière-plan? – Svish

+0

à la fois, techniquement mais je l'utilise dans la classe qui fait le travail en arrière-plan alors je n'ai jamais à m'inquiéter du motif requis d'invocation. La réponse que j'ai posté seulement devient vraiment nécessaire quand il y a beaucoup d'événements. Mais il peut évidemment être utilisé sur un seul événement. –

Questions connexes