[C#] Element in einem BackgroundWorker benutzen

UltimateKeks

Grünschnabel
Hallo tutorials.de-Community.

Ich habe ein kleines Problem mit dem BackgroundWorker in C#.
Ich versuche im DoWork-Event einer ComboBox ein neues Item hinzuzufügen. Beim Debuggen
bekomme ich folgende Fehlernachricht angezeigt:

Zusätzliche Informationen: Ungültiger threadübergreifender Vorgang: Der Zugriff auf das Steuerelement comboBox1 erfolgte von einem anderen Thread als dem Thread, für den es erstellt wurde.

Ich beschäftige mich erst seit heute mit BackgroundWorkern und Threads und würde nun gerne wissen, wie ich es erreichen kann ein Element Threadübergreifend zu erstellen.

Mit freundlichen Grüßen,
UltimateKeks :)
 
Hallo UltimateKeks

Die GUI-Elemente sind auf ihren Thread in dem sie erstellt wurden und das Fenster läuft beschränkt. Willst du irgendwas mit ihnen machen muss das in diesem Thread passieren. Dazu bietet dir jedes Control einen Dispatcher an mit dem du Code im Hauptthread ausführen kannst. Beispiel:
C#:
            var ctrl = form.Controls[0];
            ctrl.Invoke(new Action(() =>
                {
                    ctrl.Location = new System.Drawing.Point(3, 3);
                }
            ));

            ctrl.BeginInvoke(new Action(() =>
                {
                    ctrl.Size = new System.Drawing.Size(300, 200);
                }
            ));

Bei der ersten Variante wartet das so lange darauf bis in dem Thread Zeit zur Verfügung steht um den Code auszuführen, in dieser Zeit ist die Ausführung blockiert. In der zweiten Variante wird die Ausführung nicht blockiert und dein Request wartet im Hintergrund bis es freie Resourcen in dem Thread gibt.

Grüsse
Muepe
 
Hallo,

also innerhalb des DoWorkEventHandler darfst du nicht auf GUI Elemente zugreifen. Es ist auch ratsam wenn du Seiteneffekte vermeidest. Dies bedeutet du solltest z. B. nicht auf Klassenvariablen zugreifen. Beschränke dich nach Möglichkeit auf die Verwendung der DoWorkEventArgs. Wenn du den sender in BackgroundWorker castest kannst du über das ProgressChanged-Ereignis eine ProgressBar aktualisieren.

Der DoWorkEventHandler sollte im Prinzip eine Funktion f(e.Argument) = e.Result darstellen.

Du kannst ja unter e.Result das zusätzlichen Item für die ComboBox zurückgeben. Im RunWorkerCompletedEventHandler kannst du das zusätzliche Item in die ComboBox einfügen.

Es ist auch architektonisch "schön", wenn sich der DoWorkEventHandler nicht in der Form-Klasse befindet. Der RunWorkerCompletedEventHandler und der ProgressChangedEventHandler sollte sich jedoch in der Form-Klasse befinden. Somit erreichst du eine saubere Trennung von GUI und Programmlogik.
 
Zuletzt bearbeitet:
Hallo zusammen, da habe ich grad folgende Frage zu, die ganz gut passt:

Ich starte einen BackgroundWorker der zyklisch Daten von einem Ethernet device liest und eventuell auch was schreibt abhängig vom Ergebnis des Lesens. Jetzt will ich noch zusätzlich über die GUI etwas zu einer Liste hinzufügen die vom Backgroundworker auf das Ethernet device geschrieben werden soll.

Sprich die eigentlich Frage ist, wie bekomme ich die Liste zum BGW dass die Liste abgearbeitet werden kann. Da der Zugriff auf List<T> nicht atomar ist müsste ich diesen ja bei Zugriff "locken"... oder?

Ist das überhaupt so realisierbar, oder muss ich´s anders umsetzen? Mit nem zweiten BGW oder nem eigenen Thread, dem ich dann per e.Argument die Liste immer wieder übergebe?

Danke im Vorraus!

RuFF
 
Danke!
Das scheint zu funktionieren mit dem lock() und jetzt stoß ich auf das Problem, dass ich abhängig von den im BGW gelesenen DigitalInputs Elemente in der GUI ändern will...

Ich blick noch nicht ganz wie ich das mit delgates oder Invoke() oder Begininvoke() machen soll.
Im Prinzip soll der BGW in einer endlos Schleife laufen und immer wenn sich was ändert die GUI aktualisieren...

Dazu der stark gekürzte Code:

Code:
public partial class RrtCpForm : Form
    {
        public RrtCpForm( )
        {
             ...
             bgCommunicater.RunWorkerAsync( );
        }
        private void backgroundWorker1_DoWork_1( object sender, DoWorkEventArgs e )
        {
            List<IoState> DeleteList = new List<IoState>( );

            while ( !bgCommunicater.CancellationPending )
            {
                ...
                //Ausgänge schreiben
                //Eingänge lesen
                //Schreiben verifizieren
                
                -->Hier soll eine Funktion aufgerufen werden, der drei bool Variablen übergeben werden und dann Bilder in der GUI geladen werden...

                Thread.Sleep( RefreshRate );
            }// End endless comm loop

            BeckhoffController.CloseSocketConnection( );
        }
    }

Vielen Dank und Gruß!
 
Naja hat sich erledigt irgendwie kann ich aus dem BGW doch auf die GUI Elemente zugreifen...!
Und ich hab mich durch diverse Berichte verrückt machen lassen und es gar nicht erst probiert :D

Wie dem auch sei trotzdem Danke!
 
Bei Eingabeelementen kann ich das ja verstehen...
Aber ich ändere im BGW nur Bilder in der GUI.

Vielleicht klappt das auch weil es sich nur um anzeigende Elemente handelt für die gar keine anderen Events implementiert sind?
 

Neue Beiträge

Zurück