2009-04-04 1 views
2

Hinweis: Teil einer Serie: C#: Accessing form members from another class und How to access form objects from another cs file in C#. HalloZugreifen auf Klassenmitglieder mit Invoke von einem anderen Thread in C#


,

Die Idee ist, den Benutzer unter Verwendung des Memos zu benachrichtigen, wenn ein Paket in einem TCP-Client empfangen/gesendet.

Nach einigen Korrekturen, die am besten geeignete Lösung schien dies ein

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

zu sein, das ist, wie es

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

jedoch der Code eine Ausnahme auslöst Aufruf genannt wird, wegen Unsafe Faden call.Ich fand eine Lösung bei msdn, aber ich kann nicht scheinen, die Methode, die sie dort verwendet haben, zu erwerben.

Das ist mein Remake, das nicht funktioniert.

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

Fehler:

Argument '1': kann nicht von "Methode Gruppe zu

Argument 'System.Delegate' umwandeln '2': kann von 'string' to‚Objekt nicht konvertieren [ ]

Grundsätzlich versuche ich auf das Memo zuzugreifen (oder eher gesagt, Text zum Memo hinzufügen) von einem anderen Thread mit Invoke.Ich habe es nie zuvor verwendet, vielleicht deshalb missverstanden ich meinen Fehler.

+0

Wie wäre es mit einem Ereignis? – bytebender

Antwort

11

Der einfache Weg ist:

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

, die eine anonyme Methode verwendet den Job inline zu tun. Da Sie erwarten, in einem anderen Thread zu sein, können Sie auch einfach Invoke aufrufen - es ist sicher, sogar aus dem UI-Thread.

+0

Dies ist das zweite (aber nicht das letzte Mal), dass Gravell meinen Speck gerettet hat. Nur dafür können Sie diesen Samstag frei haben. Was solls, ich schätze ich kann dir auch Sonntag geben. – Chris

1

Wenn Sie mit C# 3.0 und 3.5 Framework versuchen, die folgenden

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

Und .NET 3.5 für den Action-Delegate-Typ; -p –

+0

@Marc, ich vergesse immer wieder, dass es sich um einen 3.5-Typ handelt. Warum es nicht in 2.0 hinzugefügt wurde, ist jenseits von mir :) – JaredPar

0

habe ich all dieses Cross-Thread-Geschäft zu handhaben, aber vor kurzem ging ich mit AOP, wo man einfach ein Verfahren dekoriert Führen Sie den UI-Thread aus. Hier ist ein Beispiel (von 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

Dies ist, wo AOP sollte sicherlich vor allen anderen Methoden IMHO verwendet werden.Aber für diejenigen, die mit PostSharp und AOP nicht vertraut sind, kann es schwierig sein, zu verstehen, wie es genau von Ihrem Beitrag funktioniert, und was ist die tatsächliche Einfachheit seiner Verwendung. – Groo

+0

Nun, ich würde Links zu den Lehrmaterialien bieten, die sich auf PostSharp beziehen, aber ich darf eigentlich nicht :( –

1

Ihre Implementierung geht davon aus, dass das Verfahren nicht unendlich Rekursion, da das Verhalten der InvokeRequired Eigenschaft wird es verhindern. Diese Annahme mag sich als wahr erweisen, aber es gibt kein Problem, die Funktion zu codieren, um diese Möglichkeit vollständig zu vermeiden. Hier ist, was ich vorschlage:

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

    private delegate void MemoSetter(string txt); 

    public void ThreadSafeSet(string txt) 
    { 
     Invoke(new MemoSetter(SetMemo), txt); 
    } 
Verwandte Themen