WPF ListBox Virtualisierung schraubt angezeigte Elemente

9

Problem

Wir müssen effizient eine große (& gt; 1000) Anzahl von Objekten in einem WPF-ListBox-Steuerelement anzeigen. Wir setzen auf die Virtualisierung der WPF-ListBox (über VirtualizingStackPanel), um diese Elemente effizient anzuzeigen.

Fehler : Das WPF-ListBox-Steuerelement zeigt Elemente bei Verwendung der Virtualisierung nicht korrekt an.

So reproduzieren Sie

Wir haben das Problem auf das unten gezeigte Standalone-XAML heruntergebrochen.

Kopieren Sie die XAML und fügen Sie sie in XAMLPad ein.

Anfangs gibt es kein ausgewähltes Element in der ListBox, daher haben alle Elemente erwartungsgemäß die gleiche Größe und füllen den verfügbaren Platz vollständig aus.

Klicken Sie nun auf den ersten Eintrag. Wie erwartet, wird das ausgewählte Element aufgrund unserer DataTemplate erweitert, um zusätzliche Informationen anzuzeigen.

Wie erwartet, wird dadurch die horizontale Bildlaufleiste angezeigt, da das ausgewählte Element jetzt breiter als der verfügbare Platz ist.

Jetzt verwenden Sie die Maus , um die horizontale Bildlaufleiste anzuklicken und zu ziehen.

Fehler: Die nicht ausgewählten sichtbaren Elemente werden nicht länger gedehnt, um den verfügbaren Platz zu füllen. Alle sichtbaren Elemente sollten die gleiche Breite haben.

Ist das ein bekannter Fehler? Gibt es eine Möglichkeit, dies entweder über XAML oder programmgesteuert zu beheben?

%Vor%     
Adel Hazzah 10.12.2009, 16:46
quelle

2 Antworten

3

Ich habe mehr Zeit damit verbracht, dies zu versuchen, als ich wahrscheinlich hätte, und ich konnte es nicht zum Laufen bringen. Ich verstehe, was hier vor sich geht, aber in reinem XAML habe ich Probleme herauszufinden, wie ich das Problem lösen kann. Ich denke, ich sehe, wie man das Problem löst, aber es handelt sich um einen Konverter.

Warnung: Die Dinge werden komplizierter, wenn ich meine Schlussfolgerungen darlege.

Das zugrunde liegende Problem ergibt sich aus der Tatsache, dass sich die Breite der Steuerelemente auf die Breite ihres Containers erstreckt. Wenn die Virtualisierung aktiviert ist, wird die Breite nicht geändert. In der zugrunde liegenden ScrollViewer innerhalb von ListBox entspricht die Eigenschaft ViewportWidth der angezeigten Breite. Wenn sich ein anderes Steuerelement weiter ausdehnt (Sie wählen es aus), ist ViewportWidth immer noch gleich, aber ExtentWidth zeigt die volle Breite an. Das Binden der Breite aller Steuerelemente an die von ExtentWidth sollte funktionieren ...

Aber es tut es nicht. Ich habe FontSize auf 100 gesetzt, um in meinem Fall schneller zu testen. Wenn ein Artikel ausgewählt ist, ExtentWidth="4109.13 . Wenn ich den Baum zu% Co_de% von ControlTemplate betrete, sehe ich Border . Warum der Unterschied von 2 Pixeln? ListBoxItem enthält eine Umrandung mit 2 Pixeln, wodurch der ContentPresenter etwas kleiner dargestellt wird.

Ich habe das folgende ActualWidth="4107.13" mit Hilfe von hier hinzugefügt, damit ich direkt darauf zugreifen kann die ExtentWidth:

%Vor%

Hinweis Ich habe zu diesem Zweck Style hinzugefügt.

Dann habe ich versucht, die Breite Ihres Rahmens an die ExtentWidth zu binden:

%Vor%

Aufgrund dieser 2-Pixel-Auffüllung wird die Größe der Steuerelemente jedoch in einer Endlosschleife geändert, wobei die Auffüllung 2 Pixel zum ScrollViewer hinzufügt, wodurch die Breite des Rahmens geändert wird, wodurch dem ExtentWidth 2 weitere Pixel hinzugefügt werden. usw., bis Sie den Code löschen und aktualisieren.

Wenn Sie einen Converter hinzugefügt haben, der 2 von der ExtentWidth subtrahiert, könnte das funktionieren. Wenn die Bildlaufleiste jedoch nicht existiert (Sie haben noch nichts ausgewählt), ExtentWidth . Daher funktioniert die Bindung an ExtentWidth="0" anstelle von MinWidth möglicherweise besser, sodass die Elemente korrekt angezeigt werden, wenn keine Bildlaufleiste sichtbar ist:

%Vor%

Eine bessere Lösung wäre, wenn Sie direkt den Width von MinWidth selbst in die Datenbank aufnehmen könnten. Sie könnten direkt an ExtentWidth binden, und kein Konverter wäre erforderlich. Ich habe jedoch keine Ahnung, wie ich auf diesen Gegenstand zugreifen kann.

Bearbeiten: Aus organisatorischen Gründen ist hier der Clip erforderlich, um dies zu tun. Macht alles andere überflüssig:

%Vor%     
Will Eddins 12.12.2009, 08:15
quelle
2

Danke an Wills großartige Analyse!

Basierend auf Wills Vorschlag: " Eine bessere Lösung wäre, wenn Sie die MinWidth des ListBoxItem selbst direkt in die Datenbank einbinden könnten ... Ich habe jedoch keine Ahnung, wie ich auf dieses Objekt zugreifen soll "Ich konnte das mit reinem xaml wie folgt implementieren:

%Vor%

Ich habe die Idee von Adam Nathans großartigem Buch, Windows Presentation Foundation Unleashed .

Das scheint das ursprüngliche Problem zu beheben.

Neues Problem

Sie bemerken, dass es in der XAML ein Schieberegler gibt, mit dem Sie die ListBox-Schriftart vergrößern / verkleinern können. Die Idee hier war es, dem Benutzer die Möglichkeit zu geben, den ListBox-Inhalt für eine bessere Sichtbarkeit nach oben oder unten zu skalieren.

Wenn Sie den Schieberegler zuerst ziehen, um die Schriftgröße zu erhöhen, wird die horizontale Bildlaufleiste erwartungsgemäß angezeigt. Das neue Problem besteht darin, dass die horizontale Bildlaufleiste nicht verschwindet, wenn Sie den Schieberegler nach links ziehen, um die Schriftgröße zu reduzieren .

Irgendwelche Ideen?

    
Adel Hazzah 12.12.2009 20:22
quelle

Tags und Links