Autor Beitrag
Chiyoko
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 298
Erhaltene Danke: 8

Win 98, Win Xp, Win 10
C# / C (VS 2019)
BeitragVerfasst: Mi 28.06.17 00:15 
Huhu,

ich arbeite momentan an einem Browser, einer Listview im virtuellem Modus.
Im Event, wo die Daten abgerufen werden, wird ein Threadpool erzeugt, in dessen Thread per Invoke auf die Listview
die ImageList aktualisiert wird und die Defaultbilder mit richtigen austauscht.

Trotz Threading "ruckelt" es beim scrollen an manchen Stellen ziemlich arg.

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
 ThreadPool.QueueUserWorkItem...

  private void GetThumbnail(object fileData)
        {
            string[] strData = (string[])fileData;
            lvBrowser.Invoke((MethodInvoker)delegate
            {
                Image previousImage = imgListLarge.Images[imgListLarge.Images.Keys.IndexOf(strData[0])];
                imgListLarge.Images.RemoveByKey(strData[0]);
                previousImage.Dispose();
                imgListLarge.Images.Add(strData[0], ImageLoader.GetThumbnailImage(strData[1]));
                lvBrowser.Refresh();
            });
        }




Liegt das am Invoke?
Ich kann die Generierung der Bilder auch nicht vom Delegaten trennen (2 Threads z.b.). Im Debugmodus beendet sich das Programm einfach.


Zuletzt bearbeitet von Chiyoko am Do 29.06.17 08:41, insgesamt 1-mal bearbeitet
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Mi 28.06.17 11:19 
Kannst du denn nicht mal einen Profiler dafür verwenden: Visual Studio: Running Profiling Tools With or Without the Debugger?
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mi 28.06.17 13:18 
Du spaltest ein Thread ab in dem du eigentlich nichts tust denn alles innerhalb des Invoke wird im Hauptthread ausgeführt. Das ist der Sinn von Invoke.
Gefühlt sollte es ohne Thread sogar besser funktionieren da die hier unnötige Threadsynchronisierung dann wegfällt.

Das ganze InageHandling solltest du wahrscheinlich besser irgendwie losgelöst von der ImageList (weil das auch ein Control ist und damit Threadgebunden) hinbekommen so das die Threadsynchronisierung nur noch auf das Refresh der Controls bezieht und du zumindest denn Teil mit dem Images austauschen sinnvoll in einen Thread auslagern kannst. Dazu fehlt mir jetzt gerade aber die Internas/das Wissen zum ListView. Mein Rat wäre egal was man macht versuche ohne Listview auszukommen. Das ist das mit Abstand schlechteste Control in Windows und dann von Winforms auch noch schlecht wiederveröffentlicht :(
Chiyoko Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 298
Erhaltene Danke: 8

Win 98, Win Xp, Win 10
C# / C (VS 2019)
BeitragVerfasst: Mi 28.06.17 15:55 
Ja, in der Tat hab ich bisher mit Invokes wenig getan.
Ich dachte immer, der Sinn des Invokes sei eine Aktualisierung von anderen Threads in den Hauptthread der UI?

Das Problem am Imgagehandling ist die gebundene ImageList an der Listview selbst, denn die ist wohl nicht Threadsafe.

Ohne Listview ein ähnliches Control zu bauen ist mir zu viel arbeit:D

Danke fuer die Hinweise. Ich denke, alles nochmal überdenken zu müssen.
Chiyoko Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 298
Erhaltene Danke: 8

Win 98, Win Xp, Win 10
C# / C (VS 2019)
BeitragVerfasst: Fr 30.06.17 23:18 
Die Listview schnurrt nun endlich und vom ruckeln keine Spur.

Die Anwendung stürzte ab, weil ich mich mit dem Threadpool geirrt hatte. Ich dachte, dort wird erst ein Thread gestartet, sobald die Funktion beendet wurde. Weil nun mehrere gleiche Threads parallel liefen, gabs Probleme bei der Bitmapmanipulation.

Lösung:
Einen(!) Thread beim Wechsel der Daten starten. Dieser fragt per While eine Liste mit Indexern ab, die bereits von der Listview und dessen Daten verarbeitet wurde.

Der Hauptthread kann durch einen Synchronisationkontext aktuallisiert werden, dessen Instanz im Hauptthread gestartet werden muss.

Nachvollgender Code ist noch nicht optimiert, also ein Test , funktioniert aber.


ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
        // Thread Start
        private void GetThumbnail()
        {
            int indexNumber = 1;
            int indexCounter = 0;

            while (true)
            {
                // Liste der Indexer, die per Listviewevent gefüllt wird
                if(BrowserData.ImgIndexer.Count >= indexNumber)
                {
                    FileInfo file = BrowserData.Files[BrowserData.ImgIndexer[indexCounter]];
                    Bitmap bmap = ImageLoader.GetThumbnailImage(file.FullName);

                    // Aktuallisiere Listviewdaten
                    synchronizationContext.Post(o => FillImgList(new string[] { file.Name, file.FullName }, bmap), null);

                    indexNumber++;
                    indexCounter++;
                    Thread.Sleep(500);
                }
                else
                {
                    Thread.Sleep(500);
                    continue;
                }
            }
        }


        private void FillImgList(object fileData, Bitmap  bmap)
        {
            string[] strData = (string[])fileData;
            Image previousImage = imgListLarge.Images[imgListLarge.Images.Keys.IndexOf(strData[0])];

            imgListLarge.Images.RemoveByKey(strData[0]);
            previousImage.Dispose();
            imgListLarge.Images.Add(strData[0], bmap);
        }