Question

J'ai une vue de liste que je remplis avec 8 colonnes de données utilisateur. L'utilisateur a la possibilité d'activer l'actualisation automatique, ce qui entraîne l'effacement de ListView et le repeuplement avec les dernières données de la base de données.

Le problème est que, lorsque les éléments sont effacés et repeuplés, la zone visible retourne en haut de la liste. Donc, si je regarde l'article 1000 de 2000, il est très gênant de revenir à cet article.

En gros, ce que je demande, c'est comment puis-je obtenir les distances de défilement actuelles (x et y) puis les restaurer?

Était-ce utile?

La solution

J'ai eu le même problème il y a quelque temps et j'ai fini par implémenter un algorithme pour comparer le modèle à la liste. J'ai donc ajouté / supprimé uniquement les éléments qui avaient changé. De cette façon, s’il n’y avait pas de changements en profondeur, la liste n’allait pas au début. Et ce que je voulais surtout faire, c’était l’efficacité (pour que la liste ne clignote pas).

Autres conseils

Je voulais simplement fournir des informations à ceux qui essaient désespérément d'utiliser la propriété buggy ListView.TopItem:

  1. Vous DEVEZ définir la propriété TopItem APRÈS l'appel de ListView.EndUpdate
  2. Les éléments du contrôle ListView DOIVENT avoir leur propriété Text définie sur autre chose. que String.Empty, ou la propriété ne fonctionnera pas.
  3. La définition de ListView.TopItem lève les exceptions de référence null par intermittence. Conservez toujours cette ligne de code dans un bloc Try ... Catch.

Bien sûr, cela fera que la barre de défilement de ListView passera à 0 et reviendra à l'emplacement de l'élément en haut, ce qui est gênant. Veuillez mettre à jour cette question si vous trouvez une solution de contournement à ce problème.

J'ai utilisé les éléments suivants avec succès:

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)
{ }

La propriété TopItemIndex sur ListView correspond à ce que vous recherchez. Cependant, certains bogues confirmés auraient dû être résolus dans la version VS2010 .. pas sûr (n'a pas été coché).

Quoi qu’il en soit, ma solution consiste à faire ceci:

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

Pour une raison quelconque, le fait de le configurer directement ne le met pas à jour, mais de le définir au dernier élément, puis à celui que je veux, fonctionne de manière fiable pour moi.

Regardez la propriété ListView.TopItem. Il a un index, qui devrait contenir sa position dans la liste. Recherchez cet index dans la nouvelle liste et définissez TopItem sur cet élément. Le défilement doit alors s'effectuer automatiquement.

Malheureusement, vous devrez utiliser un interop pour accéder à la position exacte dans ListView. Utilisez la fonction GetScrollInfo pour obtenir la position de défilement existante et SendMessage pour faire défiler jusqu'à la position.

Dans un article sur CodeProject nommé défilement vers un groupe doté d'un ListView cela pourrait vous guider vers la solution.

Ma solution pour maintenir la position de défilement:

Variable au niveau du formulaire:

private static int scrollSpot = 0;

Actualisation de la liste de diffusion (c.-à-d. minuterie, bouton) pour enregistrer le lieu actuel:

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

À l'intérieur de la méthode refreshTheForm pour afficher le point enregistré (placé en fin de méthode):

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

J'avais en quelque sorte le même problème. J'ai un listView que je remplis toutes les 1/2 s et quand je définis le TopItem sur un ListItem dont l'index > éléments visibles, puis la liste a sauté entre le topItem et les 2 derniers points.

Donc, pour corriger le problème, je règle le TopIterm APRÈS l'appel à 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];​

Dans mes tests, vous n’aviez même pas besoin du TopItem, bien que j’ai utilisé un int pour enregistrer l’élément sélectionné. De plus, TopItem lève une exception si vous utilisez View.Tile ou View.LargeIcon.

Ce code ne déplace pas les barres de défilement:

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

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

listView1.EndUpdate();
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top