[Windows Phone 7.5 tip] Listas infinitas

Hola a todos!

Estos días he estado jugando con el listbox de Windows Phone para hacer una lista infinita, es decir, que cuando el usuario haga scroll hasta el final de la lista, está se lo notifique al ViewModel para que se pidan más datos. De esta forma podemos evitar el cargar demasiados datos al inicio, lo que ralentizaría la carga e ir solicitándolos a medida que el usuario los necesite, podemos ver un ejemplo del funcionamiento de esta técnica en la mayoría de las aplicaciones de twitter de Windows Phone.

Método “oficial” nuevos VisualSates

Internamente un listbox se compone, entre otros controles, de un ScrollViewer que le otorga la capacidad de movimiento por contenido que ocupe más que el área de visualización de la pantalla. Con Windows Phone 7.5 Microsoft añadió dos visual groups nuevos al ScrollViewer: VerticalCompression, compuesto por los visual states CompressionTop y CompressionBottom y HorizontalCompression, que a su vez se compone de CompressionLeft y CompressionRight:

ScrollViewer Visual States
  1. <VisualStateManager.VisualStateGroups>
  2.     <VisualStateGroup x:Name=»ScrollStates»>
  3.         <VisualStateGroup.Transitions>
  4.             <VisualTransition GeneratedDuration=»00:00:00.5″/>
  5.         </VisualStateGroup.Transitions>
  6.         <VisualState x:Name=»Scrolling»>
  7.         </VisualState>
  8.         <VisualState x:Name=»NotScrolling»>
  9.         </VisualState>
  10.     </VisualStateGroup>
  11.     <VisualStateGroup x:Name=»VerticalCompression»>
  12.         <VisualState x:Name=»NoVerticalCompression»/>
  13.         <VisualState x:Name=»CompressionTop»/>
  14.         <VisualState x:Name=»CompressionBottom»/>
  15.     </VisualStateGroup>
  16.     <VisualStateGroup x:Name=»HorizontalCompression»>
  17.         <VisualState x:Name=»NoHorizontalCompression»/>
  18.         <VisualState x:Name=»CompressionLeft»/>
  19.         <VisualState x:Name=»CompressionRight»/>
  20.     </VisualStateGroup>
  21. </VisualStateManager.VisualStateGroups>

De esta forma, podríamos obtener en primer lugar una referencia al ScrollViewer dentro de nuestro ListBox y a continuación subscribirnos al cambio de estado visual del mismo, para que cuando el estado fuese uno de los cuatro estados de compresión, actuásemos cargando datos. La verdad es que este método es un poco “farragoso” y nos exige meter bastante código extra en nuestra vista. Pero además tiene una exigencia especial:

En Windows Phone 7.5 el control ScrollViewer tiene una propiedad ManipulationMode que puede recibir dos valores distintos: Control o System. El valor Control indica que se manipula como cualquier otro control de Windows Phone, mientras que el valor System indica que el sistema se encargará de la manipulación del ScrollViewer. Para que los nuevos VisualStates funcionen, el ManipulationMode debe ser System, que es el valor por defecto.

En un principio parece una buena solución, pero cuando empecé a realizar pruebas, cargando elementos de 25 en 25, observé que tras varias cargas, cuando pinchabas sobre un elemento de la lista, se seleccionaba otro al azar. Este comportamiento se corregía simplemente con ir al principio de la lista y provocar un CompressionTop… y de hecho lo he sufrido muchas veces en algunas aplicaciones de twitter como Birdsong o Mehdoh… por lo que decidí no implementar este método y revisar mis feeds a ver quien más se había enfrentado a esto y como lo habían solucionado.

Si quieres ver el artículo oficial de MSDN sobre los nuevos visual states para el scrollviewer lo tienes aquí.

Método “Bueno”

Tras un poco de búsqueda por internet di con un artículo escrito por Daniel Vaughan (si no lo seguís en twitter, es buen momento para empezar a hacerlo) en CodeProject que explicaba un método alternativo de realizar una lista infinita.

En un ScrollViewer, siempre podemos obtener dos propiedades: ScrollableHeight y VerticalOffset . Básicamente, comparando estas dos propiedades podremos saber si hemos llegado al final de la lista, lo que explica Daniel en su artículo de CodeProject es además como crear un Helper que obtenga estos valores y lance la llamada a un comando que hayamos enlazado a este helper.

Básicamente solo tenemos que usar el Helper en nuestro XAML:

ScrollViewerMonitor
  1. <Grid x:Name=»ContentPanel» Grid.Row=»1″ Margin=»12,0,12,0″>
  2.     <ListBox ItemsSource=»{Binding Items}«
  3.                 FontSize=»{StaticResource PhoneFontSizeExtraLarge}«
  4.                 monitor:ScrollViewerMonitor.AtEndCommand=»{Binding GetMoreDataCommand}«>
  5.                 
  6.     </ListBox>
  7. </Grid>

Y listo, cada vez que lleguemos al final de la lista se pedirán nuevos elementos.

Conclusión

Bueno, hoy solo quería dejaros este tip, por si os veis en la misma situación alguna vez y sobre todo reconocer el buen trabajo de Daniel Vaughan, cuya solución me parece mucho mejor que la “oficial” implementada por Microsot. Aquí os dejo un pequeño ejemplo de como usar la implementación de la lista infinita usando el segundo método para que os sirva de referencia.

Un saludo y Happy Coding!

5 comentarios sobre “[Windows Phone 7.5 tip] Listas infinitas”

  1. Excelente artículo Josué, este es el típico problema que te hace escribir cientos de lineas de código y que al final encuentras una solución muy buena.

    Un saludo.

  2. Hola, He estado mirando las listas infinitas, en un principio cuando es un listbox «normal», no tengo problemas, como en el ejemplo que adjuntas.
    Pero cuando es un listbox personalizado, es decir con
    ……

    No me salta el evento de end_scroll, me he dado cuenta que no aparece el scroll en mi listbox.

    ¿Tengo que tener alguna consideración en especial para un listbox personalizado?

Responder a santypr Cancelar respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *