Pourquoi Columns.Insert ne met-il pas à jour le DisplayIndex dans DataGridView (C #)?

StackOverflow https://stackoverflow.com/questions/227612

  •  03-07-2019
  •  | 
  •  

Question

J'insère par programme une colonne dans un DataGridView (c'est-à-dire qu'elle n'est liée à aucune table de données / base de données) comme suit:

int lastIndex = m_DGV.Columns.Count - 1;  // Count = 4 in this case
DataGridViewTextBoxColumn col = (DataGridViewTextBoxColumn)m_DGV.Columns[lastIndex];
m_DGV.Columns.RemoveAt(lastIndex);
m_DGV.Columns.Insert(insertIndex, col);  // insertIndex = 2

J'ai constaté que mes colonnes étaient visuellement hors d'usage en utilisant parfois cette méthode. Une solution de contournement consiste à définir manuellement la propriété DisplayIndex de la colonne par la suite. L'ajout de ce code "le corrige", mais je ne comprends pas pourquoi il se comporte de cette façon.

Console.Write(m_DGV.Columns[0].DisplayIndex); // Has value of 0
Console.Write(m_DGV.Columns[1].DisplayIndex); // Has value of 1
Console.Write(m_DGV.Columns[2].DisplayIndex); // Has value of 3
Console.Write(m_DGV.Columns[3].DisplayIndex); // Has value of 2
col.DisplayIndex = insertIndex;
Console.Write(m_DGV.Columns[0].DisplayIndex); // Has value of 0
Console.Write(m_DGV.Columns[1].DisplayIndex); // Has value of 1
Console.Write(m_DGV.Columns[2].DisplayIndex); // Has value of 2
Console.Write(m_DGV.Columns[3].DisplayIndex); // Has value of 3

En passant, ma grille peut augmenter son nombre de colonnes de manière dynamique. Je voulais le développer en morceaux, de sorte que chaque insertion ne nécessite pas d'allocation de colonne (et d'initialisation associée). Chaque " new " La colonne serait ensuite ajoutée en saisissant une colonne inutilisée à la fin, en l'insérant à la position souhaitée et en la rendant visible.

Était-ce utile?

La solution

Je suppose que cela est dû au fait que l'ordre des colonnes dans DataGridView ne dicte pas nécessairement l'ordre d'affichage, bien que, sans être explicitement affecté par défaut, l'ordre des colonnes dicte les valeurs de la propriété DisplayIndex. C'est pourquoi il existe une propriété DisplayIndex. Vous pouvez donc ajouter des colonnes à la collection sans effectuer d'insertions. Vous devez simplement spécifier la valeur DisplayIndex. Une mise à jour en cascade est effectuée pour tout élément ayant un DisplayIndex égal ou supérieur. Il ressort de votre exemple que la colonne insérée reçoit également la première valeur DisplayIndex ignorée.

De une question / réponse J'ai trouvé:

  

Changer le DisplayIndex entraînera   toutes les colonnes entre l'ancien   DisplayIndex et le nouveau DisplayIndex   être déplacé.

Comme avec presque toutes les collections (autres que LinkedLists), il est toujours préférable d’ajouter à une collection que d'insérer dans une collection. Le comportement que vous observez est le reflet de cette règle.

Autres conseils

J'ai quelques idées.

  1. Pourquoi ne pas adresser vos colonnes par un nom unique, plutôt que par l'index de la collection? Ils n'ont peut-être pas encore de nom, mais vous pouvez savoir qui est qui si vous leur donnez un nom qui signifie quelque chose.

  2. Vous pouvez utiliser les méthodes GetFirstColumn , GetNextColumn , GetPreviousColumn , GetLastColumn du DataGridViewColumnCollection , qui fonctionnent dans l'ordre d'affichage, et non dans la collection. Vous pouvez également parcourir la collection à l'aide d'une boucle for et de m_DGV.Columns [i] jusqu'à ce que vous trouviez celui que vous voulez.

  3. Créez un DataGridView et un DataGridViewColumnCollection hérités. DataGridView est simplement remplacé pour utiliser votre nouvelle classe de collection. Votre nouveau DataGridViewColumnCollection inclura une méthode pour adresser la collection par index d'affichage, probablement en itérant dans la collection jusqu'à ce que vous trouviez celui que vous voulez (voir n ° 2). Vous pouvez également enregistrer un dictionnaire et le maintenir à jour pour un très grand nombre de colonnes.

    Je doute de l’augmentation des performances de la tenue d’un dictionnaire, car chaque fois qu’une colonne est déplacée, vous devez essentiellement réécrire tout. De toute façon, itérer est O (n), et à moins que vous ne parliez d'opérations asynchrones avec des centaines de colonnes, vous êtes probablement d'accord.

    Vous pourrez peut-être également remplacer le opérateur [] , en supposant qu'il ne vole pas le DataGridView .

L'idée n ° 1 pourrait être la plus facile à mettre en œuvre, mais pas nécessairement la plus jolie. L'idée n ° 2 fonctionne et vous pouvez la placer dans la fonction DataGridViewColumn GetColumnByDisplayIndex (int Index) . L'idée n ° 3 est mignonne, et certainement l'approche la plus encapsulée, mais elle n'est pas vraiment triviale.

Merci à cfeduke pour ses excellents conseils. Je pensais que Insérer serait plus lent, mais le lien fourni m'a éclairé sur JUSTE COMBIEN de temps.

Cela soulève la question de savoir comment insérer et supprimer efficacement des colonnes de manière dynamique sur un DataGridView. Il semble que la conception idéale consisterait à ajouter de nombreuses colonnes en utilisant Add ou AddRange , sans jamais les supprimer. Vous pouvez ensuite simuler la suppression en définissant la propriété Visible sur false. Et vous pouvez insérer une colonne en saisissant une colonne invisible, en définissant son DisplayIndex et en la rendant visible.

Cependant, j’ai bien peur qu’il faille éviter les mines antipersonnel avec cette approche. Tout d'abord, vous ne pouvez plus indexer vos données de manière simple. Autrement dit, m_DGV.Columns [i] et m_DGV.Rows [n] .Cells [i] ne seront pas mappés correctement. Je suppose que vous pourriez créer une carte / dictionnaire pour maintenir une correspondance externe intuitive.

Étant donné que mon application (telle que conçue actuellement) nécessite l'insertion et le retrait fréquents de colonnes, cela peut valoir le coup. Quelqu'un a des suggestions?

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top