C# - GUI freeze --> ListView.Itemssource



  • Hallo,

    wenn ich versuche eine große Menge Daten an die ItemsSource der ListView zu hängen, dann bleibt die GUI für einen Moment stehen.

    Was kann ich dagegen tun?

    Ich über die Dispatcher.BeginInvoke Methode binde ich meine Datenquelle an die Itemssource

    this.Dispatcher.BeginInvoke(
                       (Action)(() =>
                       {
                           this.ItemsSource = this.DataSource;
    
                       }
                   ));
    

    Wenn mir jemand einen Tipp geben könnte, wie ich das am Besten umsetze, wäre ich sehr, sehr dankbar!!

    LG, Auraya



  • Du könntest die Daten über den BackgroundWorker laden, so bleibt die UI unbehelligt, während im Hintergrund die Daten gezogen werden.

    In diesem Fall wäre vielleicht noch "Data Virtualization" ein wichtiger Punkt, da die ListView dazu neigt bei großen Datenmengen sehr schnell, sehr langsam zu werden. Siehe http://www.codeproject.com/Articles/34405/WPF-Data-Virtualization



  • Hallo,

    vielen Dank für deine Antwort 🙂 Das Problem hierbei ist nicht das Laden der Daten. Die werden eigentlich relativ schnell ausgelesen und sind schnell verfügbar. Das passiert auch alles schon über einen Backgroundworker und da friert die GUI auch nicht ein. Aber sobald ich dann die Daten an diese ListView binde, friert die GUI kurz ein. Und ich weiß nicht, wie ich das Binden der Daten an die LISTVIEW in den Backgroundworker packen soll, weil dann eine Fehlermeldung kommt, dass ich auf die Listview nicht aus einem anderen Thread heraus zugreifen kann.

    Hab das Ganze vorher über ein Datagrid gelöst,aber nun in eine ListView umgewandelt, weil ich für das Datagrid zu wenig weiterführende Infos gefunden habe. Von der Geschwindigkeit merke ich keinen großen Unterschied.

    Hab zusätzlich ein Paging eingebaut, dass nicht soviele Datensätze aufeinmal angezeigt werden. Hier geht es um rund 1.5 mio Datensätze. Dass es bei der großen Datenmenge 3Sek brauch, um das an die ListView zu hängen, kann der Anwender durchaus verkraften. Das Problem an der Stelle ist halt nur, dass dann die GUI freezt und ich einfach nicht weiß, wie ich auf den GUI Thread zugreif ohne das alles hängt.

    LG, Auraya



  • Dazu müsstest Du schon mehr Informationen über die DataSource geben.

    Wie werden die Daten geladen? Ist DataSource ein IEnumerable, ein Array oder ne Liste?



  • Hallo 🙂

    Also ich ziehe die Daten über eine LINQ-Abfrage und erstelle daraus ein IQueryable. Ich filter die Daten dann noch über die Skip und Take-Methoden.

    Reicht das schon als Info?

    Hier die Schritte (alles im Backgroundworker)

    1. ich hole ich die Daten

    IQueryable<myType> query = (from output in context.myView
    
                                               select new myType
                                               {
    
                                                   Firmenname = output.Firmenname ,
                                                   PLZ = output.PLZ,
                                                   Ort = output.Ort,
                                                   Abteilungsname = output.Abteilungsname,
                                                   Kunde_Name = output.Kunde_Name,
                                                   Kunde_Vorname = output.Kunde_Vorname
    
                                               }
                                  ).OrderBy(n=>n.PLZ);
    

    2. Dann habe ich eine eigene ListView-Klasse geschrieben, die von der ListView erbt. Darin werden die Daten gefiltert

    this.DataSource = this.DataSource
                          .filterPLZ(_userfilter.PLZ)
                          .filterFirmenname(_userfilter.Firmenname)
                          .filterAbteilungsname(_userfilter.Abteilungsname);
    

    und 3. kommt dann das paging

    this.DataSource.Skip((_userfilter.pageIndex - 1) * _userfilter.pageSize).Take(_userfilter.pageSize);
    

    Bis dahin läuft alles sehr schnell und reibungslos. Führe ich dann aber folgenden Code aus, werden die Daten an das ListView gebunden und es hängt ca. 3sek 🙂

    this.Dispatcher.BeginInvoke(
                       (Action)(() =>
                       {
                           this.ItemsSource = this.DataSource;
    
                       }
                   ));
    


  • Linq macht Lazy Evaluation.

    Das bedeutet, die Query wird nicht, so wie Du glaubst, im Backgrounworker ausgeführt, sondern erst bei Abarbeitung (aka nach der Zuweisung innerhalb BeginInvoke)



  • Du solltest die "Materialisierung" schon im BackgroundWorker-Thread machen, d.h. z.B. ein ToList() dort verwenden. Und dann einfach diese Liste der ListView übergeben.
    Bei IQueryable werden die Daten erst dann geholt, wenn wirklich eine "Materialisierung" stattfindet, so daß in deinem Fall bisher erst bei der ItemsSource-Zuweisung (bzw. genauer: bei der Anzeige) der Datenbank-Zugriff stattfindet.



  • Hallo,

    das was bisher gesagt wurde stimmt soweit alles. Du musst früh genug materialisieren bla bla bla. Ich weiß aber worauf du hinaus willst. Wir standen vor dem selben Problem. Gerade dann wenn es um große Datenmengen geht. Auch unsere DataGrids sind visualisiert usw. aber wir beobachten das selbe Problem. Ein "IsAsnc" beim Binding hat nur bedingt was gebracht. Alles in allem kann ich dir sagen... Das ist eben WPF;-)

    Vielleicht ein paar andere Ansätze
    Du könntest nach Alternativen zu dem DataGrid von MS suchen. Telerik bietet glaube ich eins an. Kostet aber ein paar Euro. Es gibt aber noch andere. Vielleicht probierst du mal einfach durch und findest ein besseres.
    Desweiteren könntest du deine Abgefragten Daten in einer foreach in eine neue List<T> werden die dann an dein DataGrid gebunden ist. Zwischendurch machst du mal ein Update der Oberfläche. Ich weiß ganz ehrlich nicht wie sie sich verhalten wird wenn du ihr eine Zeile nach der anderen hinwirfst anstatt ne riesen Ladung zu binden aber ausprobieren könnte man es. Ich weiß, ist auch definitiv nicht die schönste Variante. Denn...wozu gibt es schon die Möglichkeit...

    Viel Glück und solltest du was haben...Lass es uns wissen;-)



  • WOW, vielen Dank. Jetzt hab ich es endlich geschnallt. 🙂
    Hab das ganze wie beschrieben mit einem Backgroundworker in eine List gepackt und damit wohl "materialisiert". Nun sind die Daten in 3sekunden da und ich kann währenddessen noch woanders hinklicken!!

    VIELEN, VIELEN DANK!! SUPER 🙂 👍 👍 So hab ich mir das vorgestellt 🙂


Log in to reply