WPF ListBox mit einem ListBox - UI-Virtualisierung und Scrolling

stimmen
26

Mein Prototyp zeigt „Dokumente“ , die „Seiten“ enthalten , die durch Miniaturbilder dargestellt werden. Jedes Dokument kann eine beliebige Anzahl von Seiten hat. Zum Beispiel könnte es mit 1000 Seiten jeweils oder irgendwo dazwischen 1000 Dokumente mit 5 Seiten jeweils oder 5 - Dokumenten sein. Die Dokumente enthalten keine andere Dokumente. In meinem XAML - Markup habe ich ein ListBox, deren ItemsTemplate Referenzen ein innerItemsTemplate , die auch eine hat ListBox. Ich möchte die zwei Ebenen der ausgewählten Elemente , so dass ich verschiedene Operationen auf Dokumente oder Seiten ausführen können (löschen, zusammenführen, um neue Position zu verschieben, etc). Die innerItemsTemplate ListBoxverwendet ein WrapPanelals das ItemsPanelTemplate.

Für das Szenario , in dem ich eine große Anzahl von Dokumenten mit wenigen Seiten habe jeweils (etwa 10.000 Dokumente mit 5 Seiten pro Stück), funktioniert das Scrollen große dank der UI - Virtualisierung durch die VirtualizingStackPanel. Allerdings habe ich Probleme , wenn ich eine große Anzahl von Seiten haben. Ein Dokument mit 1000 Seiten wird nur etwa 50 zu einem Zeitpunkt angezeigt werden (was auch immer auf dem Bildschirm paßt), und wenn ich nach unten scrollen, die äußeren ListBoxBewegungen zum nächsten Dokument, das Überspringen der 950 Seiten oder so , das nicht sichtbar waren. Zusammen mit diesen, gibt es keine , VirtualzingWrapPanelso dass der App - Speicher wirklich erhöht.

Ich frage mich, wenn ich über das den richtigen Weg werde, zumal es irgendwie schwer zu erklären! Ich möchte in der Lage sein, 10.000 Dokumente mit je 1000 Seiten angezeigt werden (nur zeigt, was auf dem Bildschirm passt), UI-Virtualisierung verwenden und auch smooth scrolling.

Wie kann ich sicherstellen, dass alle Seiten in dem Dokument die Scrollen bewegt sich durch, bevor er das nächste Dokument anzeigt, und nach wie vor UI-Virtualisierung halten? Die Scrollbar scheint nur auf das nächste Dokument zu verschieben.

Ist es logisch erscheinen , „Dokumente“ und „Seiten“ zu repräsentieren - mit meinen derzeitigen Verfahren zur Verwendung eines ListBoxin einem ListBox?

Ich würde schätzen es sehr, alle Ideen, die Sie haben. Danke.

Veröffentlicht am 30/12/2009 um 00:18
quelle vom benutzer
In anderen Sprachen...                            


5 antworten

stimmen
0

Gestatten Sie mir, diese Antwort mit einer Frage zu Vorwort: Muss der Anwender jederzeit in jedem Element in der Liste jedes einzelnen Miniatur sehen?

Wenn die Antwort auf diese Frage ‚Nein‘ ist, dann vielleicht wäre es möglich, die Anzahl der sichtbaren Seiten innerhalb der inneren Elementvorlage zu begrenzen (vorausgesetzt , dass Sie das Scrollen angegeben haben , funktioniert gut mit, sagen wir, 5 Seiten) und einen separaten verwenden ‚ausgewähltes Element‘ Vorlage , die größer ist , und zeigt alle Seiten für dieses Dokument? Billy Hollis erklärt , wie ‚Pop‘ ein ausgewähltes Element aus in einer Listbox auf dnrtv Folge 115

Beantwortet am 30/12/2009 um 06:31
quelle vom benutzer

stimmen
24

Die Antwort ist überraschend:

  • Wenn Sie ItemsControloder ListBoxwerden Sie das Verhalten , das Sie erleben, wo die Steuerrollen „von Punkt“ , so dass Sie springen über ein ganzes Dokument auf einmal, aber
  • Wenn Sie TreeViewstattdessen die Steuerung reibungslos bewegen , so dass Sie durch das Dokument und in die nächsten bewegen können, aber es wird noch in der Lage sein , virtualisieren.

Ich denke , der Grund , warum das WPF - Team dieses Verhalten gewählt ist , dass TreeViewhäufig Elemente hat , die größer als der sichtbaren Bereich ist, während die Regel ListBoxnicht ES tun.

Auf jedem Fall ist es in WPF trivial , eine machen TreeViewAussehen und wie ein handeln ListBoxoder ItemsControleinfach durch die Modifizierung ItemContainerStyle. Das ist sehr einfach. Sie können Ihre eigene oder einfach nur kopieren Sie die entsprechende Vorlage aus dem System Themendatei rollen.

So werden Sie etwas wie dieses:

<TreeView ItemsSource="{Binding documents}">
  <TreeView.ItemsPanel>
    <ItemsPanelTemplate>
      <VirtualizingStackPanel />
    </ItemsPanelTemplate>
  </TreeView.ItemsPanel>
  <TreeView.ItemContainerStyle>
    <Style TargetType="{x:Type TreeViewItem}">
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="{x:Type TreeViewItem}">
            <ContentPresenter /> <!-- put your desired container style here  with a ContentPresenter inside -->
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>
  </TreeView.ItemContainerStyle>
  <TreeView.ItemTemplate>
    <DataTemplate TargetType="{x:Type my:Document}">
      <Border BorderThickness="2"> <!-- your document frame will be more complicated than this -->
        <ItemsControl ItemsSource="{Binding pages}">
          ...
        </ItemsControl>
      </Border>
    </DataTemplate>
  </TreeView.ItemTemplate>
</TreeView>

Erste pixelbasierte Scrollen und List-Box-Stil Mehrfachauswahl arbeiten zusammen

Wenn Sie diese Technik pixelbasierte Scrollen, Ihre äußere Items zu erhalten, die die Dokumente zeigt kein ListBox sein kann (weil ListBox nicht eine Unterklasse von TreeView oder TreeViewItem ist). So verlieren Sie alle Mehrfachauswahl Unterstützung der List-Box. Soweit ich das beurteilen kann, gibt es keine Möglichkeit, diese beiden Funktionen nicht zu nutzen zusammen, ohne einige Ihren eigenen Code für eine Funktion oder die andere darunter.

Wenn Sie beiden Sätze von Funktionen in der gleichen Steuerung benötigen, haben Sie grundsätzlich mehrere Möglichkeiten:

  1. Implementieren Sie Multi-Auswahl sich in einer Unterklasse von TreeViewItem. Verwenden Sie TreeViewItem statt TreeView für die äußere Kontrolle, da sie ausgewählt mehrere Kinder werden können. In der Vorlage innerhalb ItemsContainerStyle: Fügen Sie eine CheckBox um die Content, Schablone, um die CheckBox IsSelected binden und die CheckBox mit Steuervorlage Stil das Aussehen Sie erhalten möchten. Dann Ihre eigenen Maus-Event-Handler in dem Griff Ctrl-Klick-und Shift-Click für Mehrfachauswahl.

  2. Implementieren Sie pixel gescrollt Virtualisierung selbst in einer Unterklasse von VirtualizingPanel. Dies ist relativ einfach, da die Komplexität meisten VirtualizingStackPanel des Nicht-Pixel - Scrolling und Container Recycling verwandt ist. Dan Crevier Blog hat einige nützliche infromation für VirtualizingPanel Verständnis.

Beantwortet am 30/12/2009 um 07:17
quelle vom benutzer

stimmen
13

.NET 4.5 hat nun die VirtualizingPanel.ScrollUnit="ScrollUnit"Eigenschaft. Ich konvertierte nur eine meiner TreeViews zu einer List - Box und die Leistung war deutlich besser.

Weitere Informationen hier: http://msdn.microsoft.com/en-us/library/system.windows.controls.virtualizingpanel.scrollunit(v=vs.110).aspx

Beantwortet am 20/09/2011 um 09:17
quelle vom benutzer

stimmen
37

Es ist möglich, smooth scrolling VirtualizingStackPanels in WPF 4.0 ohne Virtualisierung zu erreichen, zu opfern, wenn Sie bereit sind, Reflexion zu verwenden private Funktionalität des VirtualizingStackPanel zuzugreifen. Alles, was Sie tun müssen, ist die private IsPixelBased Eigenschaft des VirtualizingStackPanel auf true gesetzt.

Beachten Sie, dass in .Net 4.5 gibt für diesen Hack nicht erforderlich ist, wie Sie VirtualizingPanel.ScrollUnit = „Pixel“ einstellen.

Um es einfach zu machen, hier ist ein Code:

public static class PixelBasedScrollingBehavior 
{
    public static bool GetIsEnabled(DependencyObject obj)
    {
        return (bool)obj.GetValue(IsEnabledProperty);
    }

    public static void SetIsEnabled(DependencyObject obj, bool value)
    {
        obj.SetValue(IsEnabledProperty, value);
    }

    public static readonly DependencyProperty IsEnabledProperty =
        DependencyProperty.RegisterAttached("IsEnabled", typeof(bool), typeof(PixelBasedScrollingBehavior), new UIPropertyMetadata(false, HandleIsEnabledChanged));

    private static void HandleIsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var vsp = d as VirtualizingStackPanel;
        if (vsp == null)
        {
            return;
        }

        var property = typeof(VirtualizingStackPanel).GetProperty("IsPixelBased",
                                                                     BindingFlags.NonPublic | BindingFlags.Instance);

        if (property == null)
        {
            throw new InvalidOperationException("Pixel-based scrolling behaviour hack no longer works!");
        }

        if ((bool)e.NewValue == true)
        {
            property.SetValue(vsp, true, new object[0]);
        }
        else
        {
            property.SetValue(vsp, false, new object[0]);
        }
    }
}

Zur Nutzung dieses auf einer List-Box, zum Beispiel, würden Sie tun:

<ListBox>
   <ListBox.ItemsPanel>
      <ItemsPanelTemplate>
         <VirtualizingStackPanel PixelBasedScrollingBehavior.IsEnabled="True">
          </VirtualizingStackPanel>
       </ItemsPanelTemplate>
   </ListBox.ItemsPanel>
</ListBox>
Beantwortet am 26/03/2012 um 14:57
quelle vom benutzer

stimmen
4

Das funktionierte für mich. ein paar einfache Attribute scheint wird es (.NET 4.5) tun

<ListBox            
    ItemsSource="{Binding MyItems}"
    VirtualizingStackPanel.IsVirtualizing="True"
    VirtualizingStackPanel.ScrollUnit="Pixel"/>
Beantwortet am 14/02/2017 um 06:02
quelle vom benutzer

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more