2009-03-09 12 views
10

Tengo una vista de lista que estoy rellenando con 8 columnas de datos de usuario. El usuario tiene la opción de habilitar la actualización automática, lo que hace que ListView se borre y se vuelva a llenar con los datos más recientes de la base de datos.WinForms ListView, Recordando ubicación desplazada en Recargar

El problema es que cuando los artículos se borran y se vuelven a llenar, el área visible salta de nuevo a la parte superior de la lista. Entonces, si estoy mirando el artículo 1000 de 2000, es muy inconveniente volver a ese artículo.

Básicamente, lo que estoy preguntando es, ¿cómo obtengo las distancias de desplazamiento actuales (x e y) y luego las restauro?

Respuesta

4

Tuve el mismo problema que hace un tiempo y terminé implementando un algoritmo para comparar el modelo con la lista, por lo que solo agregué/eliminé elementos que habían cambiado. De esta manera, si no hubo cambios masivos, la lista no saltó al principio. Y lo principal que quería lograr era la eficiencia (para que la lista no parpadee).

+0

Esto es lo que hice. Agregué una etiqueta al primer sub artículo y luego la utilicé para hacer una comparación y solo actualizar cuando sea necesario. – GenericTypeTea

1

Mire la propiedad ListView.TopItem. Tiene un índice, que debe contener su posición en la lista. Encuentre ese índice en la nueva lista, y establezca TopItem para ese artículo, y debería hacer el desplazamiento automáticamente.

+0

El ListView.TopItem no parece funcionar. Pensé que podría tener algo que ver con la clasificación, así que lo desactivé, pero cuando configuro TopItem para un artículo y verifico la propiedad inmediatamente después, no se cambia (cambia a otro elemento, no el que especifiqué). ¿Tiene alguna idea? – TheAgent

0

Desafortunadamente, tendrá que usar algo de interoperabilidad para desplazarse a la posición exacta en el ListView. Use la función winapi GetScrollInfo para obtener la posición de desplazamiento existente y SendMessage para desplazarse a la posición.

Hay un artículo en CodeProject llamado Scrolling to a group with a ListView que podría guiarlo a la solución.

12

Sólo quería proporcionar alguna información para aquellos que desesperadamente tratan de utilizar la propiedad con errores ListView.TopItem:

  1. Debe establecer la propiedad TopItem después de llamar ListView.EndUpdate
  2. Los elementos de ListView El control DEBE tener su propiedad Text configurada en algo diferente que String.Empty, o la propiedad no funcionará.
  3. Al establecer ListView.TopItem se lanzan excepciones de referencia nula de forma intermitente. Mantenga siempre esta línea de código dentro de un bloque Try ... Catch.

Por supuesto, esto hará que la barra de desplazamiento de ListView salte a 0 y vuelva a la ubicación del elemento superior, lo que es molesto. Actualice esta pregunta si encuentra una solución a este problema.

+0

He descubierto que recibo un error de uno por uno al asignar a TopItem (es decir, se desplaza al elemento que aparece arriba del que solicito) pero si lo llamo dos veces, funciona. Buggy, dices? :-) – RichieHindle

0

Estaba teniendo el mismo problema. Tengo una lista que llené cada 1/2 segundos y cuando configuré TopItem en un ListItem cuyo índice> elementos visibles, la lista saltó entre topItem y 2 lugares atrás.

Por lo tanto, para corregir el problema, configuré TopIterm DESPUÉS de la llamada a EndUpdate.

lvB.EndUpdate(); 
lvI.EndUpdate(); 
lvR.EndUpdate(); 

if (lstEntryInts.Items.Count > 0) 
    lstEntryInts.TopItem = lstEntryInts.Items[iTopVisIdx]; 
if (lstEntryBools.Items.Count > 0) 
    lstEntryBools.TopItem = lstEntryBools.Items[iTopVisIdx]; 
if (lstEntryReals.Items.Count > 0) 
    lstEntryReals.TopItem = lstEntryReals.Items[iTopVisIdx];​ 
0

Mi solución para mantener la posición de desplazamiento:

variable de nivel de formulario:

private static int scrollSpot = 0; 

Dentro de actualización de vista de lista (es decir, automático, el botón) para almacenar la posición actual:

scrollSpot = this.listView1.TopItem.Index; 
refreshTheForm(); 

Método refreshTheForm para mostrar el punto almacenado (poner al final del método):

if (scrollSpot <= 1) 
{ 
    listView1.Items[scrollSpot].Selected = true; 
} 
else 
{ 
    listView1.Items[scrollSpot - 2].Selected = true; 
} 
listView1.TopItem = listView1.SelectedItems[0]; 
3

La propiedad TopItemIndex en ListView es lo que está buscando, sin embargo, tiene algunos errores confirmados que deberían haberse tratado en la versión VS2010 .. no estoy seguro (no lo he marcado).

De todos modos, mi solución para hacer este trabajo es hacer esto:

listViewOutput.TopItemIndex = outputList.Count - 1; 
listViewOutput.TopItemIndex = myNewTopItemIndex; 

Para algunos establecer directamente no actualizarlo razón, pero estableciéndolo en el último elemento y el que quiero funciona de forma fiable para mi.

6

que utilizó la siguiente éxito:

int topItemIndex = 0; 
try 
{ 
    topItemIndex = listView1.TopItem.Index; 
} 
catch (Exception ex) 
{ } 
listView1.BeginUpdate(); 
listView1.Items.Clear(); 
//CODE TO FILL LISTVIEW GOES HERE 
listView1.EndUpdate(); 
try 
{ 
    listView1.TopItem = listView1.Items[topItemIndex]; 
} 
catch (Exception ex) 
{ } 
0

En mis pruebas, que no necesita ni siquiera la TopItem, aunque he usado un int para guardar el elemento seleccionado. Además, TopItem arroja una excepción si está usando View.Tile o View.LargeIcon.

Este código no se mueve las barras de desplazamiento:

listView1.BeginUpdate(); 
listView1.Items.Clear(); 

// loop through your add routine 
listView1.Items.Add(lvi); 

listView1.EndUpdate();