C# ListView Elemente threadsicher aufrufen

bill

Commodore Special
Mitglied seit
18.02.2003
Beiträge
419
Renomée
4
Hallo!

Bräuchte mal eure Hilfe!! Folgendes Problem:

Ich habe einen BackgroundWorker, welcher in seiner DoWork() Methode, die Elemente einer ListView auslesen und bearbeiten soll. Die ListView ist dabei natürlich im Main-Form erstellt.

Leider funktioniert das nicht so ganz. Der Debugger meldet zur Laufzeit, dass der Thread versucht, auf Elemente zuzugreifen, die nicht von ihm erstellt wurden.
Dabei versuche ich per Delegate und Invoke an die Elemente zu kommen.

Das ganze sieht ungefähr so aus:

Code:
[COLOR="Red"]//Der delegate[/COLOR]
private delegate ListView.CheckedListViewItemCollection ListViewItemsCallback();

[COLOR="Red"]//Die DoWork Methode des BackgroundWorkers[/COLOR]
private void DoWork(object sender, DoWorkEventArgs e)
{
...
            ListView.CheckedListViewItemCollection CheckedItems;
            
            if (listView.InvokeRequired)
            {   
                [COLOR="Red"]//CheckedItems per delegate/invoke holen[/COLOR]
                ListViewItemsCallback lv = new ListViewItemsCallback(getCheckedItems);
                CheckedItems = (ListView.CheckedListViewItemCollection)this.Invoke(lv);
            }
            else
            {
                CheckedItems = listView.CheckedItems;
            }
                    
[COLOR="Red"]            //Hier mag der Debugger die ChekcedItems nicht und meckert[/COLOR]
            foreach (ListViewItem item in CheckedItems)
            {
            ..
            }
   ...
}

[COLOR="Red"]//Getter Funktion, um auf die checked items per delegate zurückzugreifen[/COLOR]
private ListView.CheckedListViewItemCollection getCheckedItems()
{
    return listView.CheckedItems;
}


Was mache ich falsch? *noahnung*

Wäre super wenn mir jemand helfen könnte!

Gruß,
bill
 
Ich kenn mich jetzt mit C# nicht besonders aus, komme aus der C/C++ Ecke, aber in Deinem Code kann ich keine Maßnahmen zur Threadsynchronisation erkennen. :]
 
Hallo!

Das sollte eigentlich dieser Abschnitt bewerkstelligen:

Code:
                //CheckedItems per delegate/invoke holen
                ListViewItemsCallback lv = new ListViewItemsCallback(getCheckedItems);
                CheckedItems = (ListView.CheckedListViewItemCollection)this.Invoke(lv);

Könnte es aber auch total falsch gemacht haben und es natürlich anders viel einfacher geht ;D
So ganz blick ich die Thread-Geschichte in C# noch nicht, deswegen frage ich ja :)

Also Ziel ist es, dass ich im BackgroundWorker (Thread) irgendwie an die Liste der Elemente der ListView rankomme. Habe das ganze jetzt ein bischen umgeschrieben, so dass ich dem BackgroundWorker 'ne Kopie Liste der Elemente als Parameter übergebe. Damit hat es dann zwar anscheinend Funktioniert, jedoch nicht wie ichs mir vorgestellt hatte.

In der Liste stehen übrigens Eingabe- und Zieldateinamen, die der Worker Thread dann alle kopieren soll.

Gruß,
bill
 
Ich seh immer noch nichts, was mit threadsicheren Code zu tun hat...
Wenn Du eine Kopie der Liste benützten willst, dann brauchst Du keine Threadsynchronisation, allenfalls während des Kopiervorgangs.
Wenn Du aus verschiedenen Threads aus eine Liste bearbeiten willst, müssen alle Methoden, welche die Liste in irgendeiner Form verändern, threadsicher ausgelegt sein.

C# bzw. VisualC bietet doch regen Support dafür, wie z.B Monitor und Synchronized methods.

Musst Dich einfach mal in der Hilfe unter "Synchronizing Data for Multithreading" einlesen.
 
Was mache ich falsch?

Du erstellst keine Kopie der Liste. getCheckedItems() liefert eine Referenz auf die Collection, auf die Du dann vom BackgroundWorker aus zugreifst. Und dann krachts. Wieso übergibst Du dem BackgroundWorker nicht einfach eine (echte) Kopie (Deep Copy) der Collection als Argument (RunWorkerAsync(<argument>)), auf die der BackgroundWorker dann ohne Locking etc. zugreifen kann?
 
Wie ich schon vorher gepostet hatte, habe ich das heute auch so gemacht, nur leider kamen da andere Schwierigkeiten auf...wäre aber schon der richtige Weg mit der DeepCopy, oder?

Was ich halt noch gerne hätte, wäre dass der WorkerThread die Elemente der ListView, die erschon abgearbeitet hat, verändert (z.B. die Background color neu setzt). Aber dass könnte ich ja dann theoretisch mit einem Delegate/Invoke machen, oder?

Werde mich jedenfalls mal nochmals zu dem Thema einlesen, ist halt schon ein Weilchen her, wo ich mich damit beschäftigt habe, und dazu war's noch in Java... *buck*

Google spuckt schon 'ne Menge zum Thema aus, aber kennt ihr da vielleicht ein paar konkrete Tipps zum einlesen?

Danke euch,
bill
 
Google spuckt schon 'ne Menge zum Thema aus, aber kennt ihr da vielleicht ein paar konkrete Tipps zum einlesen?
Benützt Du Visual C? -->> Hilfefunktion.
Oder Microsoft MSDN- und Visual C Seiten.
Nach Themen wie "Monitor", "Synchronized methods" und "Synchronizing Data for Multithreading" suchen.
 
Was ich halt noch gerne hätte, wäre dass der WorkerThread die Elemente der ListView, die erschon abgearbeitet hat, verändert (z.B. die Background color neu setzt). Aber dass könnte ich ja dann theoretisch mit einem Delegate/Invoke machen, oder?

Kann man machen. Da Du aber sowieso schon 'nen BackgroundWorker einsetzt, würde ich dafür gleich dessen Methode ReportProgress(int, object) verwenden, dann brauchst Du Dich nicht manuell darum zu kümmern, daß die Aktion im UI-Thread abläuft.

Edit:
Lesestoff:
http://www.albahari.com/threading
http://www.yoda.arachsys.com/csharp/threads
http://weblogs.asp.net/justin_rogers/articles/126345.aspx
 
Zuletzt bearbeitet:
Wenn Du den Zugriff auf ein Objekt synchronisieren möchtest, machst Du in C# am einfachsten ein lock()-Block drumherum:

z.B.:

Code:
lock (listView)
{
  // hier drin ist der Zugriff (jedenfalls auf das Objekt listView) serialisiert
}

http://msdn2.microsoft.com/en-us/library/ms173179(VS.80).aspx

Gruß,
BoMbY
 
Zurück
Oben Unten