Ungültiger threadübergreifender Vorgang



  • Guten Abend!

    Irgendwie stehe ich gerade auf dem Schlauch ... 😕

    Ich möchte ganz simpel (zum Lernen) eine ProgressBar anzeigen, während Daten in einer GridView angezeigt werden.
    Das Beispiel ist relativ sinnfrei, jedoch soll möchte ich später darauf aufbauen.7
    Nun erhalte ich oben genannte Fehlermeldung (Ungültiger threadübergreifender Vorgang).

    Ich habe dazu auch schon gelesen, dass InvokeRequired() helfen soll?! Jedoch ist mir nicht ganz klar, an welcher Stelle ich das hinzufügen muss.
    => Ich nehme mal an, dort wo auch dataGridView1 verändert wird?
    => und warum tritt die Fehlermeldung überhaupt auf?

    Hier mal mein Code:

    public Form1()
            {
                InitializeComponent();
                SetupDataGridView();
            }
    
            private void SetupDataGridView()
            {
    
                dataGridView1.ColumnCount = 6;
    
            }
    
            private void PopulateDataGridView(DataGridView dg)
            {
                string[] row0 = { "11/22/1968", "29", "Revolution 9", "Beatles", "The Beatles [White Album]" };
                string[] row1 = { "1960", "6", "Fools Rush In", "Frank Sinatra", "Nice 'N' Easy" };
                string[] row2 = { "11/11/1971", "1", "One of These Days", "Pink Floyd", "Meddle" };
                string[] row3 = { "1988", "7", "Where Is My Mind?", "Pixies", "Surfer Rosa" };
                string[] row4 = { "5/1981", "9", "Can't Find My Mind", "Cramps", "Psychedelic Jungle" };
                string[] row5 = { "6/10/2003", "13", "Scatterbrain. (As Dead As Leaves.)", "Radiohead", "Hail to the Thief" };
                string[] row6 = { "6/30/1992", "3", "Dress", "P J Harvey", "Dry" };
    
                int n = 6;
                int progress = 0;
                for (int x = 0; x < n; x++)
                {
                    dg.Rows.Add(row0);
                    dg.Rows.Add(row1);
                    dg.Rows.Add(row2);
                    dg.Rows.Add(row3);
                    dg.Rows.Add(row4);
                    dg.Rows.Add(row5);
                    dg.Rows.Add(row6);
    
                    dg.Columns[0].DisplayIndex = 3;
                    dg.Columns[1].DisplayIndex = 4;
                    dg.Columns[2].DisplayIndex = 0;
                    dg.Columns[3].DisplayIndex = 1;
                    dg.Columns[4].DisplayIndex = 2;
    
                    progress = (n + 1);
                    backgroundWorker1.ReportProgress(progress);
                }
            }
    
            private void btnStart_Click(object sender, EventArgs e)
            {
                backgroundWorker1.RunWorkerAsync();
            }
    
            private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
            {
                PopulateDataGridView(dataGridView1);
            }
    
            private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
            {
                MessageBox.Show("Fertig");
            }
    
            private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
            {
                toolStripProgressBar1.Value = e.ProgressPercentage;
            }
    

    DANKE euch vielmals schon im Voraus!!!



  • Hallo, ich kann dir leider nicht mehr ganz genau sagen, wie du das Problem lösen kannst (also mit welchem Aufruf), da du offensichtlich mit Windows Forms arbeitest. Aber das Problem ist, dass PopulateDataGridView im Background läuft (ich nehme an, dafür ist das RunWorkerAsync zuständig).

    Innerhalb dieser Methode greifst du auf die Progressbar zu, indem du mit backgroundWorker1.ReportProgress(progress); den Fortschritt updaten willst. Bei praktisch allen UI Framework (semantisch auch bei WPF, wobei es dort noch komplexer ist) ist der Zugriff auf Steuerelemente nur aus dem UI-Thread erlaubt. Bei WPF müsstest du jetzt dort sowas schreiben wie...

    Dispatcher.Invoke(() => backgroundWorker1.ReportProgress(progress));
    

    Hierdurch wird dieser Aufruf im UI-Thread getätigt. Hier musst du ansetzen.

    FG



  • Du kannst auf Fenster/Dialoge/Controls nur aus dem Thread zugreifen der sie erzeugt hat (was normalerweise der "Main Thread" der Anwendung ist). Das ist sowohl mit Windows Forms so, als auch mit WPF.

    Du versuchst nun aber auf dein DataGridView Control aus einem anderen Thread zuzugreifen, nämlich aus dem Thread deines BackgroundWorker Objekts.
    Und das ist einfach nicht erlaubt.

    D.h. du musst deine GUI Sachen im GUI Thread machen. Eine Möglichkeit das hinzubekommen ist Control.Invoke zu verwenden.

    Oder du schickst aus dem Worker-Thread einfach nur deine Progress-Reports, und schickst beim Progress-Report ein Objekt mit wo alles nötige drinnen ist, damit der GUI-Thread das Control befüllen kann.

    @/rant/
    Nö, das ReportProgress is kein Problem. Das ist ja genau dazu da um eben solche Threading Probleme zu lösen.
    Das Problem ist vielmehr dass er versucht im Worker-Thread ne DataGridView upzudaten die in nem anderen Thread erstellt wurde.
    Und Forms Controls haben auch kein Dispatcher Objekt - dafür haben sie direkt selbst eine Dispatch Funktion 😉


Anmelden zum Antworten