Laden...

[gelöst] ListView aus Worker-Thread ohne Flackern updaten

Erstellt von Nightmare vor 13 Jahren Letzter Beitrag vor 13 Jahren 3.961 Views
N
Nightmare Themenstarter:in
20 Beiträge seit 2008
vor 13 Jahren
[gelöst] ListView aus Worker-Thread ohne Flackern updaten

Hallo,

folgender Sachverhalt.
In meinem Programm existiert ein ListView Control. In diesem sind verschiedene Einträge vorhanden, die sich nach einer gewissen Zeit (einstellbar gehen wir jetzt mal von 30 sec. aus) aktualisieren können.

Momentan hab ich es folgendermaßen realisiert: Ein Thread durchläuft die Änderungen und prüft, ob Einträge des ListViews betroffen sind. Danach wird jedes einzelne Element des ListViews ausgewechselt. Vor der Prüfung rufe ich die Funktion SuspendLayout und nachher ResumeLayout des ListViews auf. Nur leider habe ich das Problem, das meine Liste natürlich flakert und sich nur sehr langsam wieder aufbaut.

Meine Frage ist nun: Wie optimiere ich das ganze? Soll ich vorher alle Einträge in eine interne Liste kopieren, hier die Änderungen durchführen, dann den ListView leeren und zum Schluss alle Elemente des ListViews neu setzen? Oder wie sieht der richtige Weg aus?

Danke schon mal für eure Hilfe

Gelöschter Account
vor 13 Jahren

Verwende Databinding. Das impliziert, das du alle Angezeigten werte in einer Datenstruktur hast. Dann kannst du die Änderungen nur innerhalb der Datenstruktur durchführen und das Invoke des GUI bei jeder änderung fällt somit weg.

edit: nein ich schreibe blödsinn... natürlich muss man immernoch invoken, da ja die änderung in einem anderen thread erfolgt.

N
Nightmare Themenstarter:in
20 Beiträge seit 2008
vor 13 Jahren

Und damit kann ich alle meine Änderungen durchführen und danach ein globales Refresh durchführen?

D
615 Beiträge seit 2009
vor 13 Jahren

Hallo

Durch DataBinding (dank INotifyPropertyChange..) wird das GUI bei Änderungen automatisch benachrichtigt und aktaulisiert sich automatisch.

Beste Grüsse

Diräkt

N
Nightmare Themenstarter:in
20 Beiträge seit 2008
vor 13 Jahren

Ich lese mir gerade mal den msdn Artikel durch. Scheint doch recht angenehm zu sein

N
Nightmare Themenstarter:in
20 Beiträge seit 2008
vor 13 Jahren

Ok habs mir durch gelesen und würde jetzt wie folgt vorgehen.

  1. Eine neue BindingSource erstellen und das Event ListChanged abfangen.
  2. Bei Änderungen die Items der BindingSource.List abändern.
  3. Die Items des ListViews durch den Listener für das ListChanged Event der BindingSource ändern lassen.

Wann genau tritt das ListChanged Event der BindingSource ein?
Wahrscheinlich schon in diesem Falle:


for (int i = 0; i < count(zähler); i++)
     this.myBindingSource.List[i] = newElement; //Hier beim ersten Durchgang

Was müsste ich denn dafür tun, damit z.B. der ListView erst nach durchlaufen der Schleife erneuert wird, oder bin ich hiermit komplett auf dem Holzweg?

Gelöschter Account
vor 13 Jahren

~~Du bist auf dem Holzweg.

Du bindest die Datenstruktur an die Listview. Damit hast du schon mal die GUI Seite fertig.

Danach macht dein Thread nur die Änderungen an der Datenstruktur und nicht an der Bindingsource oder an der Listview.~~

edit: nein ich schreibe blödsinn... natürlich muss man immernoch invoken, da ja die änderung in einem anderen thread erfolgt.

N
Nightmare Themenstarter:in
20 Beiträge seit 2008
vor 13 Jahren

...
Du bindest die Datenstruktur an die Listview. Damit hast du schon mal die GUI Seite fertig.
...

Wie genau mache ich das bzw. wie meinst du das?

Gelöschter Account
vor 13 Jahren

myListView.DataSource = XXX

Dies hättest du aber auch alleine herausfinden können.

N
Nightmare Themenstarter:in
20 Beiträge seit 2008
vor 13 Jahren

Da war ich auch schon drauf gekommen 😃

Leider besitzen meine ListViews keine Eigenschaft DataSource!
Anscheinend muss ich mir ein geerbtes ListView erstellen, welches dieses Modell abbildet!
Ich verwende übrigens DotNET Framework 2.0. Wird wahrscheinlich die Erklärung sein.

Erscheint mir jetzt aber sehr aufwendig für ein, meiner Meinung nach, simples Problem 😕

4.942 Beiträge seit 2008
vor 13 Jahren

Hallo zusammen,
reden wir hier von WPF oder WinForms? Weil das WinForms-ListView kein DataBinding unterstützt... du müßtest dann auf das DataGridView wechseln (s.a. Vergleich DatagridView - ListView).

N
Nightmare Themenstarter:in
20 Beiträge seit 2008
vor 13 Jahren

So ich habs jetzt folgendermaßen gelöst.


//Zuerst einmal implementiere ich die Funktion "LockWindowUpdate"
//der "user32.dll"
[DllImport("user32.dll")]
private static extern bool LockWindowUpdate(IntPtr hWndLock);

//Wenn mein Thread jetzt geänderte Daten hat läuft die Methode 
//so ab

//Fensterupdate unterdrücken
LockWindowUpdate(this.myListView.Handle);
//Neue Items fürs ListView
this.myListView.Items.Clear();
this.myListView.AddRange(this.myListViewItems);
//Fenster neu zeichnen
LockWindowUpdate(IntPtr.Zero);

So damit bekomme ich nur noch einen Redraw was die ganze Sache annähernd perfekt macht!
Ich finde es vollkommen ok so. Trotzdem Danke für eure Hinweise.

F
10.010 Beiträge seit 2004
vor 13 Jahren

Du kommst nicht zufällig von VB6?

Weil da wird auch immer ein Problem so gelöst, indem man einen schlechten Weg benutzt und das dann mit "geht ja" einfach hinnimmt, statt es vernünftig zu machen.
Das hätte hier auch nicht länger gedauert.

Stichwort VirtualMode

N
Nightmare Themenstarter:in
20 Beiträge seit 2008
vor 13 Jahren

Nein das nicht, ich gebe dir auch Recht, dass mein vorgeschlagener Weg nicht der beste ist.
Aber er funktioniert halt.

Egal auf jeden Fall habe ich mir mal deinen Vorschlag angeschaut und ich werds auf jeden Fall mal ausprobieren 😉. Danke für den Hinweis