2009-04-04 8 views
2

Note: Partie d'une série: C#: Accessing form members from another class et How to access form objects from another cs file in C#.Accès aux membres de la classe avec Invoke à partir d'un thread différent en C#


Bonjour,

L'idée est d'informer l'utilisateur en utilisant le mémo lorsqu'un paquet est reçu/envoyé dans un client TCP.

Après quelques corrections, la solution la plus appropriée semble être celui-ci

public string TextValue 
    { 
     set 
     { 
      this.Memo.Text += value + "\n"; 
     } 
    } 

Voilà comment il est appelé

var form = Form.ActiveForm as Form1; 
    if(form != null) 
     form.TextValue = "Test asdasd"; 

Cependant, en appelant le code lance une exception, à cause de fil non sécurisée appel.J'ai trouvé une solution à msdn, mais je ne peux pas sembler acquérir la méthode qu'ils ont utilisée là.

Ceci est mon remake, qui ne fonctionne pas.

private void SetTextMemo(string txt) 
    { 
     if(this.Memo.InvokeRequired) 
     { 
      this.Invoke(SetTextMemo,txt); //error here 
     } 
     else 
     { 
      this.Memo.Text += txt + "\n"; 
     } 
    } 

erreurs:

argument '1': ne peut pas convertir les 'groupe de procédé' à 'System.Delegate'

Argument '2': ne peut pas convertir les 'chaîne' à « objet [ Fondamentalement, j'essaye d'accéder à la note (ou plus probablement a ajouté, ajoutez le texte au mémo) d'un autre fil en utilisant Invoke. Je ne l'ai jamais utilisé avant, peut-être c'est pourquoi je me trompe.

+0

Qu'en est-il de l'utilisation d'un événement? – bytebender

Répondre

11

Le plus simple est:

this.Invoke((MethodInvoker)delegate { 
    this.Memo.Text += txt + "\n"; 
}); 

qui utilise une méthode anonyme pour faire la ligne de travail. Puisque vous attendez pour être sur un autre thread, vous pouvez aussi bien appeler Invoke - il est sûr, même à partir du thread UI.

+0

Ceci est le 2ème (mais pas la dernière fois) que Gravell a sauvé mon bacon. Juste pour ça, vous pouvez avoir ce samedi de congé. Que diable je suppose que je peux vous donner dimanche aussi. – Chris

1

Si vous utilisez C# 3.0 et le 3.5 cadre les opérations suivantes

if (this.Memo.InvokeRequired) { 
    this.Invoke((Action)(() => SetTextMemo(txt))); 
} 
+0

Et .NET 3.5 pour le type de délégué d'action ;-p –

+0

@ Marc, je n'oublie pas que c'est un type 3.5. Pourquoi il n'a pas été ajouté dans 2.0 est au-delà de moi :) – JaredPar

0

Je l'habitude de gérer toute cette croix-fil, mais récemment, je suis allé avec AOP, où vous décorez simplement une méthode pour exécuter sur le thread de l'interface utilisateur. Voici un exemple (de PostSharp):

public class FormsThreadAttribute : OnMethodInvocationAspect 
{ 
    public override void OnInvocation(MethodInvocationEventArgs eventArgs) 
    { 
    Form f = (Form)eventArgs.Delegate.Target; 
    if (f.InvokeRequired) 
     f.Invoke(eventArgs.Delegate, eventArgs.GetArgumentArray()); 
    else 
     eventArgs.Proceed(); 
    } 
} 
+0

C'est là que AOP devrait certainement être utilisé avant toute autre méthode à mon humble avis.Mais pour ceux qui ne sont pas familiers avec PostSharp et AOP, il peut être difficile de comprendre comment cela fonctionne exactement à partir de votre message, et quelle est la simplicité réelle de son utilisation. – Groo

+0

Eh bien, je voudrais offrir des liens vers le matériel d'enseignement relatif PostSharp, mais je ne suis pas autorisé à :( –

1

Votre mise en œuvre suppose que la méthode ne sera pas infiniment récursion parce que le comportement de la propriété InvokeRequired va l'empêcher. Cette hypothèse peut s'avérer être vraie, mais il n'y a aucun problème à coder la fonction pour éviter complètement cette possibilité. Voici ce que je suggère:

private void SetMemo(string txt) 
    { 
     Memo.Text = txt; 
    } 

    private delegate void MemoSetter(string txt); 

    public void ThreadSafeSet(string txt) 
    { 
     Invoke(new MemoSetter(SetMemo), txt); 
    } 
Questions connexes