Guybrush Threepwood Geschrieben 5. Februar 2007 Geschrieben 5. Februar 2007 Ich hab ne Form mit ner ListBox drauf und einen Thread der da Einträge hinzufügen soll. Damit das klappt musste ich mir jetzt extra eine Funktion schreiben die den String für die ListBox als Parameter bekommt und dann einfach nur Listbox.Items.Add() aufruft. Dann musste ich mir ein Delegate auf die Funktion anlegen um die dann im Thread per Invoke aufrufen zu können Gibts da nicht nen bequemeren Weg? Unter C mit der WinAPI hab ich in so fällen einfach immer SendMessage aufgerufen und fertig, aber die Funktion scheint in C# nur für das Compact Framework zu geben... Zitieren
denis-cubic Geschrieben 7. Mai 2007 Geschrieben 7. Mai 2007 Ist zwar nicht ganz sauber aber mit der Komponente "BackgroundWorker" ist sowas möglich. Oder die saubere Methode mit Delegation Zitieren
Kati82 Geschrieben 23. März 2009 Geschrieben 23. März 2009 Hallo, bin neu hier und hoffe mir kann jemand helfen. Ich nähere mich auch gerade dem Thema Multithreading, allerdings unter C++. Ich habe jetzt eine CLI-Anwendung erstellt, welche eine Listbox enthält. In dieser möchte ich einfach ein paar Zwischenschritte ausgeben lassen, aber von einem anderen Thread aus. Zudem ist der Thread auch noch in einer anderen Klasse. Ich weiß nicht, ob das eventuell das Problem ist. Jedenfalls habe ich ja schon mitbekommen, dass man da mit diesem delegate arbeiten muss. Und nach tagelangem ausprobieren, habe ich endlich eine Version, bei der der Compiler nicht meckert. Das Problem ist nur, dass sich bei der Listbox gar nichts tut. Könnte mir da eventuell jemand bitte behilflich sein? Was mache ich falsch. Hier mal mein Quellcode (hoffentlich reicht das aus): Klasse von dem Window-Form: delegate void AddListItemMethod(String^ str); AddListItemMethod^ myDelegate; void AddListItemMethod(String^ str) { lbResults->Items->Add(str); lbResults->Update(); } Aufruf im Thread in einer anderen Klasse PingTest::Form1^ AddListItemDelegate = gcnew PingTest::Form1; AddListItemDelegate->AddListItemMethod("huhu"); Ich hoffe, ich habe das Thema nicht komplett missverstanden. Ich bin für jeden Hilfe dankbar. Viele Grüße Kati82 Zitieren
VaNaTiC Geschrieben 23. März 2009 Geschrieben 23. März 2009 Ja, das mit dem delegates ist ziemlich heftig, aber einmal verstanden ist das sehr sicher. Nicht wie in anderen Sprachen, da muss man sich 100%ig selbst drum kümmern. Hab ein Beispiel für Dich aus einem Test von mir: public delegate void VoidColorStringDelegate(Color color, string text); public void Log(Color color, string text) { if ( text == null || text.Length == 0 ) return; if ( rtbLogs.InvokeRequired ) { rtbLogs.Invoke(new VoidColorStringDelegate(Log), new Object[] {color, text}); return; } int iPos = rtbLogs.Text.Length; rtbLogs.AppendText(text); rtbLogs.Select(iPos, iPos+text.Length); rtbLogs.SelectionColor = color; rtbLogs.Select(rtbLogs.Text.Length, 0); rtbLogs.ScrollToCaret(); } public void LogLine(Color color, string text) { Log(color, text+"\r\n"); } Zitieren
Kati82 Geschrieben 23. März 2009 Geschrieben 23. März 2009 Hallo, danke erst mal für die schnelle Hilfe. Ich habe aber trotzdem noch ein paar Verständnisprobleme. Der Thread, von welchen aus ich die Zwischenergebnisse anzeigen möchte, befindet sich ja bei mir in einer anderen Klasse. Das ist in obigen Beispiel ja nicht der Fall. Gibts da noch irgendwas zu beachten?Ich habe das mit dem InvokeRequired mal ausprobiert. Komischerweise ist diese Bedingung nicht erfüllt. Wenn ich die Hilfe in der MSDN richtig deute, bedeutet das, das kein entsprechendes Handle für dieses Control vorhanden ist. Die Listbox ist doch aber vorhanden, wieso sollte ich doch mal ein Handle erstellen?Die Zeile mit dem Invoke bekomme ich irgendwie noch nicht richtig hin. Vermutlich liegts an der Syntax von C++/CLI. Aber wenn ich das richtig verstanden habe, müsste ich in meinem Fall im groben so vorgehen:public delegate void AddStringDelegate(String^ str); public void AddString(String^ str) { if ( listbox.InvokeRequired ) { listbox->Invoke(new AddStringDelegate (AddString?), .?.); return; } else { listbox->Items->Add(str); } } Ich begreife noch nicht ganz wie ich bei dem Invoke die Parameter angeben soll. Gibts da eventuell noch ein paar Tipps und Hinweise? Viele Grüße Kati82 Zitieren
Guybrush Threepwood Geschrieben 23. März 2009 Autor Geschrieben 23. März 2009 Ich begreife noch nicht ganz wie ich bei dem Invoke die Parameter angeben soll. Einfach als weitere Parameter von Invoke. listbox->Invoke(new AddStringDelegate (AddString), str); [/PHP] Zitieren
Kati82 Geschrieben 23. März 2009 Geschrieben 23. März 2009 Wenn ich das so mache kommen folgene Fehlermeldungen: error C3867: 'PingTest::Form1::AddString': function call missing argument list; use '&PingTest::Form1::AddString' to create a pointer to member error C3350: 'PingTest::Form1::AddStringDelegate' : a delegate constructor expects 2 argument(s) Wenn ich mich an den Vorschlag der ersten Fehlermeldung halte und schreibe: lbResults->Invoke(gcnew AddStringDelegate (&PingTest::Form1::AddString), str); kommt danach nur noch diese Fehlermeldung: error C3352: 'void PingTest::Form1::AddString(System::String ^)' : the specified function does not match the delegate type 'void (System::String ^)' Den String-Parameter bei AddString nochmal zu übergeben bringt nichts. Läuft denn das bei C++/CLI so komplett anders ab? Kati82 Zitieren
VaNaTiC Geschrieben 23. März 2009 Geschrieben 23. März 2009 Wichtig zu beachten sind 3 Dinge: - ... delegate result name(params); ist nur die Deklaration einer Methodensignatur, damit die Invoke-Methode korrekt aufgerufen werden kann - man sollte versuchen immer in der Methode selbst zu prüfen, ob ein Invoke notwendig ist, so dass der Zugriff von "Außen" transparent bleibt. Ergo je "näher" am Element, desto besser - das Control weiss über InvokeRequired() ob ein Recall mittels Invoke(...) notwendig ist. So wie ich die Hilfe verstanden hatte, prüft das die Aufrufende Thread-ID mit der GUI-Thread-ID. Wie allerdings die Parameterübergabe in C++ genau ausschaut kann ich Dir nicht sagen, mein Beispiel war in C#, aber ich vermute ist ähnlich und in der MSDN beschrieben. Zitieren
VaNaTiC Geschrieben 23. März 2009 Geschrieben 23. März 2009 (bearbeitet) Aus der MSDN für C++: array<Object^>^myStringArray = {myString}; myFormControl1->Invoke( myFormControl1->myDelegate, myStringArray ); Der zweite Parameter von Invoke() ist Object[], d.h. auch wenn die zu invokende Methode nur 1 Parameter hat ist das halt ein Object[0] = str Bearbeitet 23. März 2009 von VaNaTiC Zitieren
Kati82 Geschrieben 23. März 2009 Geschrieben 23. März 2009 Es hat endlich geklappt. Ich habe schon so oft das Beispiel von der MSDN nachzumachen, aber wenn man sich natürlich die falsche Funktion raussucht, wo nur das Delegate übergeben wird und keine Parameter, dann kann es ja nicht klappen. :upps Ich danke euch nochmal für eure Hilfe. Viele Grüße Kati82 Zitieren
Empfohlene Beiträge
Dein Kommentar
Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.