WPF - VirtualizingStackPanel запрашивает все элементы при переходе в режим редактирования в DataGrid
Я использую DataGrid
с CellEditingTemplates
, Как ItemsSource
используется виртуализированная коллекция данных (решение AlphaChiTech), которая по запросу извлекает только страницы размером 100 единиц одновременно.
Он прекрасно работает до тех пор, пока ячейка не будет дважды нажата в форме редактирования, затем VirtualizingStackPanel
запрашивает все элементы один за другим. Конечно, в качестве побочного эффекта все страницы запрашиваются в конце концов.
Есть ли способ обойти эту проблему?
Редактировать:
Я нашел обходной путь, который может помочь людям в моей ситуации:
В конце концов я заметил, что VirtualizingStackPanel не запрашивает все элементы при условии, что высота строки остается неизменной после перехода в форму редактирования. До обхода проблемы моя форма редактирования была немного выше.
Теперь я установил MinHeight элементов управления в ячейках (как нормальных, так и редактируемых) таким образом, чтобы при переключении на форму редактирования высота не изменялась.
К сожалению, это работает только при определенных условиях. Есть случаи, в которых это не будет работать:
С помощью
RowDetailsTemplate
, Как только это видно, виртуализация нарушается. Я предполагаю, что детали строки принадлежат самой строке, поэтому высота строки снова увеличивается.Вызов события Reset of the Collection соответственно CollectionView. По моему опыту, это вообще убийца виртуализации данных с
DataGrids
,Уничтожая
Count
коллекции (это также не вызывает событие Reset).
Интересно, что увеличение Count
из коллекции действительно работал. Но мне пришлось расширить возможности AlphaChiTech (к счастью, источники на github), потому что там нет никакого способа изменить Count
без поднятия события Reset из коробки (по крайней мере, я не нашел). Так же DataGrid's
элементы должны быть обновлены сразу же после этого, иначе будет выдано исключение о том, что ItemsControl
и у коллекции есть несоответствующее состояние.
Детали строки для меня необязательны, но удаление элементов без нарушения виртуализации данных имеет решающее значение. Таким образом, проблема все еще остается. Мой обходной путь, скорее всего, поможет людям с коллекциями фиксированного размера, но, к сожалению, не я сам.
1 ответ
Обходной путь
Я нашел решение этой проблемы самостоятельно. Это временное решение предназначено для использования редактируемых коллекций с виртуализацией данных в WPF (виртуализированная коллекция только для чтения данных может быть реализована без обходных путей).
Во-первых, ряды должны быть одинаковыми. Одна из моих проблем заключалась в том, что CellEditingTemplates
были выше, чем CellTemplates
, Таким образом, каждый раз, когда форма редактирования была запущена, DataGrid
достал все предметы коллекции. Настройка MinHeight
из CellTemplates
чтобы соответствовать высоте CellEditingTemplates
сделал трюк.
По-видимому, RowDetailsTemplate
принадлежат строке, поэтому, когда она становится видимой, она изменяет высоту строки и, следовательно, нарушает виртуализацию данных. Таким образом, может быть лучше пойти без подробностей строки и использовать шаблон основной детали, где "детали" отображаются за пределами DataGrid
, Позже я пытаюсь реализовать это прямо сейчас (не полностью реализованная первая попытка сработала достаточно хорошо, чтобы сказать, что это не создает никаких проблем). Мне пришло в голову одно исключение для деталей строки: если детали строки всегда видны и каждый элемент имеет детали строки одинакового размера, то это может сработать. Идея заключалась бы в том, что высота строк тогда была бы одинаковой, но, поскольку в моем приложении только несколько элементов из всей коллекции нуждаются в деталях, я не пробовал этот подход.
Во-вторых, уменьшение количества - то есть, чтобы удалить элементы - и сброс элементов по коллекции или DataGrid
вызвал также получение всех предметов. Обходной путь здесь заключается в замене существующей коллекции новым объектом коллекции из тех же элементов всякий раз, когда элемент добавляется или удаляется. К счастью, эта новая коллекция также виртуализирована с данными. Так что он все еще эффективен во времени, беглый и пользователь не заметит этого. Но по-прежнему существует проблема, если такое "обновление" выполняется, когда элемент выбран в DataGrid
, Здесь приходит неприятный обходной путь: я реализовал два события в ViewModel
, который управляет виртуальной коллекцией. Это PreVirtualizedRefresh
а также PostVirtualizedRefresh
, View
с DataGrid
подписывается на них и отменяет выбор каждого элемента в DataGrid
на PreVirtualizedRefresh
и на PostVirtualizedRefresh
индекс отмененного выбора (если он запомнен) может быть выбран снова. Позже один все еще не работает для меня.
Важно то, что с этими обходными путями (с использованием альтернативного шаблона основной детали и обновлением с новым объектом коллекции и отменой выбора элементов) виртуализация данных не будет нарушена.
замечания
Из всех решений для виртуализации, которые я пробовал при решении этих проблем, я считаю, что решение AlphaChi является лучшим.
WPF определенно не предназначен для виртуализации данных. Его преемник UWP, с другой стороны, даже имеет собственный интерфейс для виртуализации данных. Поскольку у меня нет ни одного проекта UWP, я не мог бы попробовать сам, но я думаю, это было бы очень весело. Тем не менее, UWP не имеет родной DataGrid
Таким образом, виртуализированные данные коллекции должны быть переданы Lists
или сторонний DataGrids
, Таким образом, здесь также необходим компромисс.