WPF ListBox med en ListBox - UI Virtualisering og rulling

stemmer
26

Mine prototype viser dokumenter som inneholder sider som er representert av miniatyrbilder. Hvert dokument kan ha et ubegrenset antall sider. For eksempel kan det være 1000 dokumenter med 5 sider hver, eller 5 dokumenter med 1000 sider hver, eller et sted innimellom. Dokumenter ikke inneholder andre dokumenter. I min XAML markering har jeg en ListBox, som ItemsTemplate referanser en innerItemsTemplate som også har en ListBox. Jeg vil at 2 nivåer av utvalgte elementer slik at jeg kan utføre ulike operasjoner på dokumenter eller sider (slette, flette, flytte til nytt sted, etc). Den innerItemsTemplate ListBoxbenytter en WrapPanelsom ItemsPanelTemplate.

For scenario der jeg har et stort antall dokumenter med noen få sider hver (si, 10000 dokumenter med 5 sider hver), rullingen fungerer stor takk til UI Virtualization ved VirtualizingStackPanel. Men jeg har problemer hvis jeg har et stort antall sider. Et dokument med 1000 sider vil bare vise ca 50 om gangen (hva passer på skjermen), og når jeg ruller nedover, de ytre ListBoxflyttes til neste dokumentet, hoppe på 950 sider eller så som ikke var synlig. Sammen med det, er det ingen VirtualzingWrapPanelslik app minnet virkelig øker.

Jeg lurer på om jeg kommer om dette på riktig måte, spesielt siden det er liksom vanskelig å forklare! Jeg ønsker å være i stand til å vise 10000 dokumenter med 1000 sider hver (bare viser hva passer på skjermen), ved hjelp av UI virtualisering, og også jevn rulling.

Hvordan kan jeg sørge for at rulle beveger seg gjennom alle sidene i dokumentet før den viser det neste dokumentet, og fortsatt beholde UI virtualisering? Rullefeltet ser ut til å bare gå til neste dokumentet.

Betyr det virke logisk å representere dokumenter og sider - med min nåværende metode for å bruke en ListBoxi en ListBox?

Jeg vil veldig mye pris på noen ideer du har. Takk skal du ha.

Publisert på 29/12/2009 klokken 23:18
kilden bruker
På andre språk...                            


5 svar

stemmer
0

Vennligst la meg forord dette svaret med et spørsmål: Har brukeren må se hver og miniatyr innenfor hvert element i listen til enhver tid?

Hvis svaret på det spørsmålet er 'nei', så kanskje det ville være mulig å begrense antall synlige sider i den indre elementmal (gitt at du har angitt rullingen fungerer godt med, sier, 5 sider) og bruke en separat 'valgt element' mal som er større og viser alle sider for at dokumentet? Billy Hollis forklarer hvordan 'pop' et valgt element i en listeboksen på dnrtv episode 115

Svarte 30/12/2009 kl. 05:31
kilden bruker

stemmer
24

Svaret her er overraskende:

  • Hvis du bruker ItemsControleller ListBoxdu vil få atferden du opplever, hvor kontroll ruller "av posten" slik at du hopper over et helt dokument samtidig, men
  • Hvis du bruker TreeViewi stedet, vil kontrollen rulle jevnt slik at du kan bla gjennom dokumentet og inn i den neste, men det vil fortsatt være i stand til å virtualisere.

Jeg tror grunnen til WPF teamet valgte denne oppførselen er at TreeViewofte har elementer som er større enn det synlige området, mens vanligvis ListBoxes ikke.

I alle fall er det trivielt i WPF å lage en TreeViewtitt og handle som en ListBoxeller ItemsControlved ganske enkelt å endre ItemContainerStyle. Dette er veldig grei. Du kan rulle din egen eller bare kopiere over passende mal fra systemet tema filen.

Så du vil ha noe sånt som dette:

<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>

Får pikselbasert rulling og ListBox-stil Multi å arbeide sammen

Hvis du bruker denne teknikken for å få pikselbasert rulling, ytre ItemsControl som viser dokumentene kan ikke være en ListBox (fordi ListBox er ikke en underklasse av Utforsker eller TreeViewItem). Dermed mister alle ListBox er Multi støtte. Så vidt jeg kan fortelle, er det ingen måte å bruke disse to funksjonene sammen uten å ta med noen av din egen kode for en funksjon eller den andre.

Hvis du trenger begge settene med funksjonalitet i den samme kontrollen, har du i utgangspunktet flere alternativer:

  1. Implementere multi-utvalget selv i en underklasse av TreeViewItem. Bruk TreeViewItem istedenfor Utforsker for ytre kontroll, siden det gjør at flere barn til å bli valgt. I malen inne ItemsContainerStyle: Legg en avkrysnings rundt ContentPresenter, mal binde boksen for å IsSelected, og style av i boksen med kontroll mal for å få det utseendet du ønsker. Deretter legge til dine egne muse hendelseshåndterere å håndtere Ctrl-klikk og Shift-klikk for Multi.

  2. Implementere pixel-rullet virtualisering selv i en underklasse av VirtualizingPanel. Dette er forholdsvis enkel, siden det meste av VirtualizingStackPanel kompleksitet er relatert til ikke-piksel rulling og beholder resirkulering. Dan Crevier blogg har noen nyttige infromation for å forstå VirtualizingPanel.

Svarte 30/12/2009 kl. 06:17
kilden bruker

stemmer
14

.NET 4.5 har nå VirtualizingPanel.ScrollUnit="ScrollUnit"eiendommen. Jeg bare konvertert en av mine treeviews til en ListBox og forestillingen ble merkbart bedre.

Mer informasjon her: http://msdn.microsoft.com/en-us/library/system.windows.controls.virtualizingpanel.scrollunit(v=vs.110).aspx

Svarte 20/09/2011 kl. 08:17
kilden bruker

stemmer
38

Det er mulig å oppnå jevn rulling VirtualizingStackPanels i WPF 4.0 uten å ofre virtualisering hvis du er forberedt på å bruke refleksjon for å få tilgang til privat funksjonalitet VirtualizingStackPanel. Alt du trenger å gjøre er å sette den private IsPixelBased eiendommen av VirtualizingStackPanel til sann.

Merk at i .Net 4.5 er det ikke behov for dette hack som du kan sette VirtualizingPanel.ScrollUnit = "Pixel".

For å gjøre det veldig enkelt, her er noen kode:

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]);
        }
    }
}

For å bruke dette på en ListBox, for eksempel, ville du gjøre:

<ListBox>
   <ListBox.ItemsPanel>
      <ItemsPanelTemplate>
         <VirtualizingStackPanel PixelBasedScrollingBehavior.IsEnabled="True">
          </VirtualizingStackPanel>
       </ItemsPanelTemplate>
   </ListBox.ItemsPanel>
</ListBox>
Svarte 26/03/2012 kl. 13:57
kilden bruker

stemmer
6

Dette fungerte for meg. Synes et par enkle attributter vil gjøre det (.NET 4.5)

<ListBox            
    ItemsSource="{Binding MyItems}"
    VirtualizingStackPanel.IsVirtualizing="True"
    VirtualizingStackPanel.ScrollUnit="Pixel"/>
Svarte 14/02/2017 kl. 06:02
kilden bruker

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