WPF — VirtualizingStackPanel запрашивает все элементы при переходе в режим редактирования в DataGrid

Я использую DataGrid с CellEditingTemplates. В качестве ItemsSource используется виртуализированная коллекция данных (решение AlphaChiTech), которая извлекает только страницы размером 100 элементов за раз по запросу.

Он прекрасно работает до тех пор, пока ячейка не будет дважды нажата в форме редактирования, затем VirtualizingStackPanel запрашивает все элементы один за другим. Конечно, в качестве побочного эффекта в конечном итоге запрашиваются все страницы.

Есть ли способ обойти эту проблему?

Изменить:

Я нашел обходной путь, который может помочь людям в моей ситуации:

В конце концов я заметил, что VirtualizingStackPanel не запрашивает все элементы при условии, что высота строки остается прежней после переключения на форму редактирования. До обхода моя форма редактирования была немного выше.

Сейчас я настроил MinHeight элементов управления в ячейках (как обычных, так и редактируемых) таким образом, чтобы при переходе на форму редактирования высота не менялась.

К сожалению, это работает только при определенных условиях. Есть случаи, когда это не сработает:

  • Использование RowDetailsTemplate. Как только он виден, виртуализация нарушена. Я предполагаю, что детали строки принадлежат самой строке, поэтому высота строки снова увеличивается.

  • Вызов события Reset для Collection соответственно для CollectionView. По моему опыту, это вообще убийца для виртуализации данных с DataGrids.

  • Уменьшение Count коллекции (это также не вызывает проблемы с событием сброса).

Интересно, что увеличение Count коллекции сработало. Но пришлось усилить возможности АльфаЧиТека (благо исходники есть на гитхабе), т.к. там нет возможности поменять Count без поднятия события Reset из коробки (по крайней мере я не нашел). Кроме того, элементы DataGrid's должны быть обновлены сразу же после этого, иначе будет выдано исключение, указывающее, что ItemsControl и коллекция имеют несогласованное состояние.

Детали строк для меня необязательны, но удаление элементов без нарушения виртуализации данных имеет решающее значение. Таким образом, проблема все еще остается. Мой обходной путь, скорее всего, поможет людям с коллекциями фиксированного размера, но, к сожалению, не мне.


person Dima    schedule 28.02.2016    source источник


Ответы (1)


Временное решение

Я сам нашел обходное решение для этой проблемы. Этот обходной путь предназначен для использования виртуализированных редактируемых коллекций данных в WPF (виртуализированная коллекция только для чтения реализуется без обходных путей).

Во-первых, ряды должны быть одного размера. Одна из моих проблем заключалась в том, что CellEditingTemplates были выше, чем CellTemplates. Таким образом, каждый раз, когда запускалась форма редактирования, DataGrid извлекала все элементы коллекции. Установка MinHeight CellTemplates в соответствии с высотой CellEditingTemplates сделала свое дело.

По-видимому, RowDetailsTemplate принадлежит строке, поэтому, когда он становится видимым, он меняет высоту строки и, следовательно, нарушает виртуализацию данных. Таким образом, может быть лучше обойтись без сведений о строке и использовать шаблон master-detail, где «подробности» отображаются за пределами DataGrid. Последнее я пытаюсь реализовать прямо сейчас (не полностью реализованная первая попытка сработала достаточно хорошо, чтобы сказать, что это не создает никаких проблем). Мне пришло в голову одно исключение для сведений о строках: если сведения о строках всегда видны и каждый элемент имеет сведения о строках одинакового размера, тогда это может сработать. Идея заключалась бы в том, чтобы высота строк была одинаковой, но, поскольку в моем приложении только несколько элементов всей коллекции нуждаются в деталях, я не пробовал этот подход.

Во-вторых, уменьшение количества — то есть удаление элементов — и сброс элементов в коллекции или DataGrid также вызвали выборку всех элементов. Обходной путь здесь заключается в замене существующей коллекции новым объектом коллекции из тех же элементов всякий раз, когда элемент добавляется или удаляется. К счастью, эта новая коллекция также виртуализирована. Таким образом, он по-прежнему экономичен по времени, беглый, и пользователь этого не заметит. Но все еще остается проблема, если такое «обновление» выполняется, когда элемент выбран в DataGrid. Вот неприятный обходной путь: я реализовал два события в ViewModel, который управляет виртуализированной коллекцией. Это PreVirtualizedRefresh и PostVirtualizedRefresh. View с DataGrid подписываются на них и отменяют выбор каждого элемента в DataGrid на PreVirtualizedRefresh и на PostVirtualizedRefresh индекс невыбранного элемента (если он запоминается) может быть выбран снова. Позже один все еще не работает хорошо для меня.

Важно то, что с этими обходными путями (с использованием альтернативного шаблона master-detail и обновлением с новым объектом коллекции и отменой элементов) виртуализация данных не будет нарушена.

Примечания

Из всех решений виртуализации, которые я пробовал при решении этих проблем, я считаю решение AlphaChi лучшим.

WPF определенно не создан с учетом виртуализации данных. С другой стороны, его преемник UWP имеет даже собственный интерфейс для виртуализации данных. Поскольку у меня нет ни одного проекта UWP, я не мог попробовать сам, но я думаю, это было бы очень весело. При этом у UWP нет собственного DataGrid, поэтому виртуализированные коллекции данных должны передаваться Lists или стороннему DataGrids. Так что здесь тоже нужен компромисс.

person Dima    schedule 28.06.2016