Почему Columns.Insert не обновляет DisplayIndex в DataGridView (C #)?

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

  •  03-07-2019
  •  | 
  •  

Вопрос

Я вставляю столбец в DataGridView программно (то есть не привязан ни к каким таблицам / базам данных) следующим образом:

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

Я обнаружил, что мои столбцы визуально вышли из строя, иногда используя этот метод. Обходной путь - вручную установить свойство DisplayIndex столбца. Добавление этого кода «исправляет его», но я не понимаю, почему он так себя ведет.

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

Кроме того, моя сетка может динамически увеличивать количество столбцов. Я хотел увеличить его по частям, чтобы каждая вставка не требовала выделения столбцов (и соответствующей инициализации). Каждый " новый " После этого столбец будет добавлен путем захвата неиспользуемого столбца с конца, вставки его в желаемое положение и отображения его.

Это было полезно?

Решение

Я подозреваю, что это связано с тем, что порядок столбцов в DataGridView не обязательно определяет порядок отображения, хотя без явного присвоения по умолчанию порядок столбцов определяет значения свойства DisplayIndex. Вот почему существует свойство DisplayIndex, поэтому вы можете добавлять столбцы в коллекцию без выполнения вставок - вам просто нужно указать значение DisplayIndex, и для всех объектов с равным или большим DisplayIndex происходит каскадное обновление. Из вашего примера видно, что вставленный столбец также получает первое пропущенное значение DisplayIndex.

Из вопроса / ответа , который я нашел:

  

Изменение DisplayIndex приведет к   все колонны между старым   DisplayIndex и новый DisplayIndex   быть сдвинутым.

Как и почти во всех коллекциях (кроме LinkedLists), всегда лучше добавлять в коллекцию чем вставить в коллекцию. Поведение, которое вы видите, является отражением этого правила.

Другие советы

У меня есть пара идей.

<Ол>
  • Как насчет адресации ваших столбцов уникальным именем, а не индексом в коллекции? Возможно, у них уже нет имени, но вы можете отслеживать, кто есть кто, если вы дадите им имя, которое что-то значит.

  • Вы можете использовать методы GetFirstColumn , GetNextColumn , GetPreviousColumn , GetLastColumn DataGridViewColumnCollection класс, который работает по порядку отображения, а не по порядку в коллекции. Вы также можете просто перебирать коллекцию, используя цикл for и m_DGV.Columns [i] , пока не найдете нужный.

  • Создайте унаследованные DataGridView и DataGridViewColumnCollection . DataGridView просто переопределяется для использования вашего нового класса коллекции. Ваш новый DataGridViewColumnCollection будет содержать метод для обращения к коллекции по отображаемому индексу, предположительно путем итерации по коллекции, пока вы не найдете тот, который вам нужен (см. # 2). Или вы можете сохранить словарь и обновлять его для очень большого числа столбцов.

    Я сомневаюсь в увеличении производительности хранения словаря, так как каждый раз, когда столбец перемещается, вам, по сути, приходится переписывать все это. В любом случае, перебор это O (n), и если вы не говорите асинхронные операции с сотнями столбцов, вы, вероятно, в порядке.

    Возможно, вы также сможете переопределить оператор this [] , если он не испортит DataGridView .

  • Идея № 1 может быть самой простой для реализации, но не обязательно самой красивой. Идея № 2 работает, и вы можете поместить ее в функцию DataGridViewColumn GetColumnByDisplayIndex (int Index) . Идея №3 хороша и, безусловно, наиболее инкапсулирована, но не совсем тривиальна.

    Спасибо cfeduke за отличный совет. Я подозревал, что Insert будет медленнее, но предоставленная ссылка проинформировала меня о том, СКОЛЬКО медленнее.

    Это поднимает вопрос о том, как эффективно динамически вставлять и удалять столбцы в DataGridView. Похоже, идеальным вариантом было бы добавить множество столбцов с помощью Add или AddRange , а затем никогда их не удалять. Затем вы можете смоделировать удаление, установив для свойства Visible значение false. И вы можете вставить столбец, захватив невидимый столбец, установив его DisplayIndex и сделав его видимым.

    Тем не менее, я подозреваю, что при таком подходе можно избежать наземных мин. Прежде всего, вы больше не можете индексировать свои данные простым способом. То есть m_DGV.Columns [i] и m_DGV.Rows [n] .Cells [i] не будут отображаться должным образом. Я полагаю, вы могли бы создать карту / словарь для поддержки внешнего интуитивного отображения.

    Поскольку мое приложение (как оно разработано в настоящее время) требует частой вставки и удаления столбцов, оно того может стоить. У кого-нибудь есть предложения?

    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top