2009-06-23 30 views
36

¿Es posible implementar desplazamiento suave en un WPF listview como funciona en Firefox?
Cuando el navegador Firefox contenía todos los elementos listview y mantienes presionado el botón central del mouse (pero no el lanzamiento), y lo arrastras, debe desplazar suavemente los elementos listview. Cuando lo suelte, debería detenerse.¿Es posible implementar desplazamiento suave en una vista de lista de WPF?

Parece que esto no es posible en winforms, pero me pregunto si está disponible en WPF?

Respuesta

64

Puede lograr el desplazamiento suave, pero se pierde la virtualización artículo, así que básicamente se debe utilizar esta técnica sólo si tiene algunos elementos de la lista:

información aquí: Smooth scrolling on listbox

Ha intentado Marco:

ScrollViewer.CanContentScroll="False" 

en el cuadro de lista?

De esta manera, el desplazamiento es manejado por el panel en lugar del ListBox ... Sin embargo, perderá la virtualización, por lo que podría ser más lento si tiene mucho contenido.

+1

Gracias Pop. ¿Qué es la virtualización? –

+10

La virtualización es donde el contenido dentro de un VirtualizingStackPanel (que es el Panel de elementos predeterminado para ListBoxs y tal) no representa el diseño de los elementos hasta/a menos que el elemento sea visible. Por lo tanto, con numerosos elementos o visualmente complejos, puede ofrecer un impulso significativo en el rendimiento, ya que solo genera la interfaz de usuario para un pequeño porcentaje a la vez. Más información aquí: http://msdn.microsoft.com/en-us/library/system.windows.controls.virtualizingstackpanel.aspx – rmoore

+1

Haciendo esto está cambiando de desplazamiento lógico a físico (suponiendo que está utilizando un StackPanel que implementa IScrollInfo). Si todavía desea el desplazamiento lógico, pero para hacerlo sin problemas, esto no ayuda – Schneider

3

Intente configurar la propiedad adjunta ScrollViewer.CanContentScroll a falsa en la ListView. Pero como dijo Pop Catalin, se pierde virtualización de elementos, lo que significa que todos los elementos de la lista se cargan y completan a la vez, no cuando se necesita mostrar un conjunto de elementos, por lo que si la lista es enorme, podría causar problemas de memoria y rendimiento

+0

Gracias. Ya veo, sí, eso estaría bien. Pero cuando establezco esta propiedad en falso, ¿cómo implementaré el desplazamiento? Al igual que si hago clic con el botón central + arrastrar hacia abajo, quiero que se desplace hacia abajo una cantidad sin problemas. ¿O esta característica ya está incorporada pero activada por esta propiedad? –

+0

Es activado por la propiedad de forma automática. No estoy seguro de la función de desplazamiento del botón del medio, pero la lista aún debe desplazarse. El nombre CanContentScroll es un poco engañoso, imho :) Lo intentaré para verificarlo. – Eddie

+0

Gracias Eddie. Sí, nombre extraño seguro. Así que este desplazamiento cuando la propiedad está habilitada funciona con la barra de desplazamiento, ¿verdad? –

10

De hecho, es posible hacer lo que está pidiendo, aunque requerirá una buena cantidad de código personalizado.

Normalmente, en WPF, ScrollViewer utiliza lo que se conoce como Desplazamiento lógico, lo que significa que se desplazará elemento por elemento en lugar de desplazarse. Las otras respuestas cubren algunas de las formas en que puede cambiar el comportamiento del Desplazamiento lógico al de Desplazamiento físico. La otra forma es hacer uso de los métodos ScrollToVertialOffset y ScrollToHorizontalOffset expuestos tanto por ScrollViwer como por IScrollInfo.

Para implementar la parte más grande, el desplazamiento cuando se presiona la rueda del mouse, necesitaremos hacer uso de los eventos MouseDown y MouseMove.

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

En el MouseDown, vamos a registrar la posición actual del ratón, lo que vamos a utilizar como punto de relativa para determinar la dirección en que se desplazan en. En el movimiento del ratón, vamos a obtener el componente ScrollViwer de ListView y luego Desplácese en consecuencia.

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

Hay algunas áreas que carece ya que es sólo una prueba de concepto, pero definitivamente debe empezar en la dirección correcta. Para hacer que se desplace constantemente una vez que el mouse se aleja del punto inicial MouseDown, la lógica de desplazamiento podría ir a un DispatcherTimer o algo similar.

0

intente configurar la altura del listview como automático y envolverlo en un visor de desplazamiento.

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

No se olvide de mencionar la altura de ScrollViewer Espero que esto ayude ....

+0

Esto no funciona si hay una gran cantidad de datos en la lista –

1

Si utiliza .NET 4.5 (o 4.0 si está dispuesto a cortar un poco) entonces hay una respuesta over here.

Cuestiones relacionadas