2009-06-23 13 views
36

Czy można zaimplementować płynne przewijanie w WPF listview, tak jak działa w Firefoksie?
Gdy przeglądarka Firefox zawiera wszystkie elementy listview, a przytrzymasz środkowy przycisk myszy (ale nie zostanie zwolniony), i przeciągnij go, powinien płynnie przewijać elementy listview. Po zwolnieniu powinien się zatrzymać.Czy można włączyć płynne przewijanie w widoku listy WPF?

Wygląda na to, że nie jest to możliwe w WinForm, ale zastanawiam się, czy jest dostępny w WPF?

Odpowiedz

64

można osiągnąć płynne przewijanie ale tracisz punkt wirtualizacji, więc w zasadzie powinien użyć tej metody tylko wtedy, gdy masz kilka elementów w liście:

informacji tutaj: Smooth scrolling on listbox

Próbowałeś ustawienie:

ScrollViewer.CanContentScroll="False" 

na listy?

W ten sposób przewijanie jest obsługiwane przez panel, a nie przez listBox ... Tracisz wirtualizację, jeśli robisz tak, więc może to być wolniejsze, jeśli masz dużo treści.

+1

Dzięki Pop. Czym jest wirtualizacja? –

+10

Wirtualizacja polega na tym, że zawartość wewnątrz obiektu VirtualizingStackPanel (który jest domyślnym ItemPanelem dla ListBox i tym podobnych) nie renderuje układu elementów do/dopóki element nie jest widoczny. Dzięki licznym lub wizualnie złożonym elementom może znacznie zwiększyć wydajność, ponieważ generuje tylko ui za niewielki procent. Więcej informacji tutaj: http://msdn.microsoft.com/en-us/library/system.windows.controls.virtualizingstackpanel.aspx – rmoore

+1

Powoduje to przełączenie z przewijania logicznego na fizyczne (zakładając, że używasz StackPanel, który implementuje IScrollInfo). Jeśli nadal chcesz logiczne przewijanie, ale aby go wygładzić, to nie pomoże – Schneider

3

Spróbuj ustawić dołączony własność ScrollViewer.CanContentScroll do fałszywego na ListView. Jednak, jak powiedział , pop Catalin traci wirtualizację elementów, co oznacza, że ​​wszystkie elementy na liście są ładowane i zapełniane natychmiast, a nie wtedy, gdy wymagany jest zestaw elementów do wyświetlenia - więc jeśli lista jest ogromna, może to spowodować pewne problemy z pamięcią i wydajnością.

+0

Dzięki. Rozumiem, tak, byłoby w porządku. Ale kiedy ustawię tę właściwość na fałsz, w jaki sposób zaimplementuję zwój? Tak jak wtedy, gdy kliknę środkowym przyciskiem myszy + przeciągnę w dół, chcę, aby płynnie przewijał się w dół o pewną ilość. Czy ta funkcja jest już wbudowana, ale aktywowana przez tę właściwość? –

+0

Jest on automatycznie aktywowany przez usługę. Nie jestem pewien co do funkcji przewijania środkowego przycisku, ale lista powinna nadal przewijać. Nazwa CanContentScroll jest trochę myląca, imho :) Postaram się ją dokładnie sprawdzić. – Eddie

+0

Dzięki Eddie. Tak, dziwne imię na pewno. Więc to przewijanie, gdy właściwość jest włączona, działa z paskiem przewijania, prawda? –

10

Rzeczywiście jest możliwe zrobienie tego, o co prosisz, choć będzie to wymagało sporo niestandardowego kodu.

Zwykle w WPF ScrollViewer wykorzystuje tzw. Przewijanie logiczne, co oznacza, że ​​będzie przewijany przedmiot po elemencie, a nie o wartość przesunięcia. Pozostałe odpowiedzi obejmują niektóre sposoby zmiany zachowania przewijania logicznego na działanie przewijania fizycznego. Innym sposobem jest wykorzystanie metod ScrollToVertialOffset i ScrollToHorizontalOffset odsłoniętych zarówno przez ScrollViwer, jak i IScrollInfo.

Aby zaimplementować większą część, przewijanie po naciśnięciu kółka myszki będzie wymagało użycia zdarzeń MouseDown i MouseMove.

<ListView x:Name="uiListView" 
      Mouse.MouseDown="OnListViewMouseDown" 
      Mouse.MouseMove="OnListViewMouseMove" 
      ScrollViewer.CanContentScroll="False"> 
    .... 
</ListView> 

W MouseDown, mamy zamiar nagrać aktualną pozycję myszy, które będziemy używać jako względna punktu w celu określenia w jakim kierunku możemy przewijać. W ruch myszy, mamy zamiar dostać komponent ScrollViwer ListView, a następnie Przewiń go odpowiednio.

private Point myMousePlacementPoint; 

private void OnListViewMouseDown(object sender, MouseButtonEventArgs e) 
{ 
    if (e.MiddleButton == MouseButtonState.Pressed) 
    { 
     myMousePlacementPoint = this.PointToScreen(Mouse.GetPosition(this)); 
    } 
} 

private void OnListViewMouseMove(object sender, MouseEventArgs e) 
{ 
    ScrollViewer scrollViewer = ScrollHelper.GetScrollViewer(uiListView) as ScrollViewer; 

    if (e.MiddleButton == MouseButtonState.Pressed) 
    { 
     var currentPoint = this.PointToScreen(Mouse.GetPosition(this)); 

     if (currentPoint.Y < myMousePlacementPoint.Y) 
     { 
      scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset - 3); 
     } 
     else if (currentPoint.Y > myMousePlacementPoint.Y) 
     { 
      scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset + 3); 
     } 

     if (currentPoint.X < myMousePlacementPoint.X) 
     { 
      scrollViewer.ScrollToHorizontalOffset(scrollViewer.HorizontalOffset - 3); 
     } 
     else if (currentPoint.X > myMousePlacementPoint.X) 
     { 
      scrollViewer.ScrollToHorizontalOffset(scrollViewer.HorizontalOffset + 3); 
     } 
    } 
} 

public static DependencyObject GetScrollViewer(DependencyObject o) 
{ 
    // Return the DependencyObject if it is a ScrollViewer 
    if (o is ScrollViewer) 
    { return o; } 

    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(o); i++) 
    { 
     var child = VisualTreeHelper.GetChild(o, i); 

     var result = GetScrollViewer(child); 
     if (result == null) 
     { 
      continue; 
     } 
     else 
     { 
      return result; 
     } 
    } 
    return null; 
} 

Jest to niektóre obszary pozbawione jak to tylko proof of concept ale powinien zdecydowanie należy zacząć w dobrym kierunku. Aby mieć ciągłe przewijanie po przesunięciu myszy od początkowego punktu MouseDown, logika przewijania mogła przejść do DispatcherTimer lub czegoś podobnego.

0

spróbuj ustawić wysokość listy jako automatyczną i zawijaj ją w przeglądarce przewijania.

<ScrollViewer IsTabStop="True" VerticalScrollBarVisibility="Auto"> 
    <ListView></ListView> 
</ScrollViewer> 

Nie zapomnij wspomnieć, wysokość ScrollViewer Hope this helps ....

+0

To nie działa, jeśli w widoku list jest dużo danych –

1

Jeśli używasz .NET 4.5 (lub 4.0, jeśli jesteś gotów włamać się trochę), to istnieje odpowiedź over here.

Powiązane problemy