Почему Columns.Insert не обновляет DisplayIndex в DataGridView (C #)?
-
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]
не будут отображаться должным образом. Я полагаю, вы могли бы создать карту / словарь для поддержки внешнего интуитивного отображения.
Поскольку мое приложение (как оно разработано в настоящее время) требует частой вставки и удаления столбцов, оно того может стоить. У кого-нибудь есть предложения?