Forum: PC-Programmierung c# Invoke auf Methode anwenden


von Sascha (Gast)


Lesenswert?

Hallo,
ich habe eine Hardware die mir mittels eigenständigen thread empfangene 
Daten zur verfügung stellt.

Diese Daten werden in einer form verarbeitet und entsprechend angezeigt.

Nun hat meine form mehrere Elemente welche ich mit diesen empfangenen 
Daten füllen will, daher suche ich nach einer Möglichkeit nicht erst die 
einzelnen Anzeigeelemente per Invoke zu synchronisiern sondern direkt 
beim "ankommen" meiner Daten das ganze per invoke zu machen.
1
delegate void  HandleSerialDataCallback(int e, sSerDat SerDat);
2
 
3
public void HandleSerialData(sSerDat SerDat)
4
{
5
     HandleSerialDataCallback callback = new HandleSerialDataCallback(HandleSerialData);
6
     this.Invoke(callback, new object[] { e, SerDat });
7
}

*Leider funktiert das so nicht!*

Liegt das daran dass ein Invoke generell nur auf GUI-Elemente angewandt 
werden kann oder weil ich etwas falsch mache?

Könnt Ihr mir bitte einen Tipp geben wie ich das machen muss ohne für 
jede TextBox, jedes Label und jede Checkbox ein eigenes Invoke zu 
erstellen?

von Borislav B. (boris_b)


Lesenswert?

Ich hoffe ich habe dein Problem richtig verstanden ;-)


Ich mache das meist so: ich baue eine Methode, die einen Block Daten 
entgegennimmt (z.B. als struct oder Klasse). Diese Methode aktualisiert 
dann alle Steuerelemente entsprechend.

Die Methode rufe ich dann einfach aus dem anderen Thread auf, und 
übergebe ihr den neuen Datenblock, den ich (woher auch immer) habe:

this.Invoke((MethodInvoker)(() => MeineTolleMethode(neueDatenHier, neue 
DatenDa, neueDatenTralala)));

So braucht es dann nur einen einzigen Invoke.

von Oliver R. (superberti)


Lesenswert?

Hi,

schau Dir mal die Klasse BackgroundWorker an, diese hat einen 
Progress-Event, der synchron zum GUI-Thread abgearbeitet wird. Dem 
kannst Du beliebige Parameter geben und es läuft mit Forms und WPF.
Sehr nützliche Klasse!

Gruß,

von Sven H. (dsb_sven)


Lesenswert?

Was bekommst du denn für eine Fehlermeldung?

Nicht jeder hat Lust das erst nachzuprogrammieren ;-)

von ich (Gast)


Lesenswert?

Vermutlich heißt die Fehlermeldung "Ungültiger threadübergreifender 
Vorgang: Der Zugriff auf das Steuerelement erfolgte von einem anderen 
Thread als dem Thread, für den es erstellt wurde."

Das liegt in der Tat daran dass man die GUI nicht aus jedem beliebigen 
thread manipulieren kann. Invoke ist das Mittel zur Wahl...

von Markus V. (Gast)


Lesenswert?

Sascha schrieb:
> ...nicht erst die einzelnen Anzeigeelemente per Invoke zu synchronisiern > 
sondern direkt beim "ankommen" meiner Daten das ganze per invoke zu
> machen.

Üblicherweise macht man sowas aus dem empfangenden Thread heraus nicht 
per Control.Invoke sondern über ein Event. Der Mechanismus ist der 
gleiche, nur "hängt" das Event nicht an einem Control, sondern an der 
Klasse des Datenmodells im Hintergrund. In Deinem Fall also die Klasse, 
die die seriellen Daten empfängt. Der Code könnte in etwa aussehen wie 
folgt:
1
public delegate void HandleSerialDataCallback(int e, sSerDat SerDat);
2
3
public class DataModel
4
{
5
    public event HandleSerialDateCallback SerialDataAvailable;
6
7
    ...
8
9
    private void EmpfangeSerielleDaten()
10
    {
11
        ...
12
        int intData = ...
13
        sSerDat receivedData = ...
14
        if (SerialDataAvailable != null)
15
            SerialDataAvailable.Invoke(intData,receivedData);
16
        ...
17
    }
18
}

Die GUI-Klasse registriert sich bei der Instanz von DataModel als 
Konsument des Events:
1
class Xyz
2
{
3
    private DataModel model;
4
5
    public Xyz()
6
    {
7
        model = new DataModel();
8
        model.SerialDataAvailable += SerialDataAvailableHandler;
9
    }
10
11
    private void SerialDataAvailableHandler(int intData, sSerDat serDat)
12
    {
13
        ...
14
        // hier die Controls per Control.Invoke aktualisieren, da
15
        // die Methode im Call-Context des aufrufenden Threads auf-
16
        // gerufen wird (hier der Thread, der die Daten seriell empfängt).
17
        ...
18
    }
19
}

Der Vorteil dieses Verfahrens ist die Entkopplung des Daten-Modells von 
der GUI, da alle GUI-Components nur in der betreffenden GUi-Klasse 
verwendet werden. Viel Erfolg!

Gruß
Markus

von Sascha (Gast)


Lesenswert?

Hallo und danke für die Hilfe!

Ich verstehe nicht ganz was "SerialDataAvailable" macht?
SerialDataAvailable ist bei mir immer null, ich muss das doch irgendwo 
referenzieren, kannst du mir da bitte nochmal einen kleinen Denkanstoss 
geben, Danke!

von Markus V. (Gast)


Lesenswert?

Hi Sascha,

SerialDataAvailable ist ein .net-Event. Näheres dazu findest Du unter 
http://msdn.microsoft.com/en-us/library/17sde2xt%28v=VS.100%29.aspx.

Ich will nochmal versuchen, den Sachverhalt mit anderen Worten zu 
erläutern.

Die Klasse A implementiert ein Datenmodell und hat ein public Event, das 
bei Änderung des Datenmodells ausgelöst wird. In Deinem Fall wäre das 
die Klasse, die Daten von der seriellen Schnittstelle liest. Das Event 
wird ausgelöst, wenn Deine Daten vollständig vorliegen (im obigen 
Beispiel der code in der Methode EmpfangeSerielleDaten).

Die Klasse B interessiert sich für Änderungen am Datenmodell im 
Hintergund und hat deshalb eine Referenz auf das Objekt der Klasse B und 
meldet sich bei dieser als Konsument des Events an (Code im Konstruktor 
Xyz). Hierzu muß die Klasse B eine Methode mit der passenden Signatur 
implementieren. Diese Signatur wird durch das Event (bzw. das 
zugrundeliegende Delegate) festgelegt.

Gruß
Markus

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.