I am using a DataGrid
with CellEditingTemplates
. As ItemsSource
a data virtualized collection is used (the AlphaChiTech solution), which only fetches pages of a size of 100 items at a time on demand.
It works great until a cell is double clicked into the editing form, then the VirtualizingStackPanel
requests all items one after another. Of course as a side effect all pages are requested eventually.
Is there a way to workaround this issue?
Edit:
I found a workaround, which might help people in my situation:
Eventually I observed that the VirtualizingStackPanel did not request all items under the condition that the row height stays the same after switching to the editing form. Before the workaround my editing form was slightly higher.
Now I set up the MinHeight of the controls in the cells (both normal and editing) in such a way that with switching to the editing form the height does not change.
Unfortunately this works only under certain conditions. There are cases in which it will not work:
Using RowDetailsTemplate
. As soon as it is visible the virtualization is broken. I assume that the row details belong to the row its self, so the row height increases again.
Raising the Reset event oft the Collection respectivelly the CollectionView. In my experience this is generally the killer for data virtulization with DataGrids
.
Decraesing the Count
of the collection (This is also without throwing the Reset event a problem).
It is interesting that increasing the Count
of the collection did work. But I had to enhance the capabilities of the AlphaChiTech (fortunatly the sources are on github), because there is no way there to change the Count
without raising the Reset event out-of-the-box (atleast I did not found). Also the DataGrid's
items have to be refreshed immediatly afterwards or else an exception is thrown stating that the ItemsControl
and the collection do have an inconsistend state.
The row details are optional to me, but deleting items without breaking the data virtualization is crucial. Thus, the problem still remains. My workaround will most likely help people with collections of fixed size, but unfortunately not myself.
The Workaround
I found a workaround-solution for this problem myself. This workaround is for usage of data-virtualized editable collections in WPF (a data-virtualized read-only collection is implementable without workarounds).
First, the rows have to be uni-sized. One of my problems was that the CellEditingTemplates
were higher than the CellTemplates
. So each time the editing form was triggered, the DataGrid
fetched all the items of the collection. Setting the MinHeight
of the CellTemplates
to match the height of the CellEditingTemplates
did the trick.
Apparrently, the RowDetailsTemplate
belong to the row, so when made visible it changes the height of the row and therefore breaks the data virtualization. So, it might be best to go with out row details and use a master-detail pattern, where the "details" are displayed outside of the DataGrid
. Latter I am trying to implement right now (a not-fully implemented first try worked well enough to tell that this does not make any trouble). One exception for the row details did come to mind to me: If the row details are always visible and each item has row details of same size, then it might work. The idea would be that the height of the rows is then uni-sized, but as in my application only few items of the whole collection need details I did not try this approach out.
Second, decreasing the count - meaning to delete items - and reseting the items over the collection or the DataGrid
triggered also the fetching of all items. The workaround here is to replace the existing collection with a new collection object of the same items, whenever an item is added or deleted. Fortunatly, this new collection is data-virtualized, too. So it still is time-efficient, fluent and the user would not notice it. But there is still a problem if such a "refresh" is executed while an item is selected in the DataGrid
. Here comes a nasty workaround: I implemented two events in the ViewModel
, which manages the virtualized collection. These are PreVirtualizedRefresh
and PostVirtualizedRefresh
. The View
with the DataGrid
subscribes to them and deselects each item in the DataGrid
on PreVirtualizedRefresh
and on PostVirtualizedRefresh
the deselected item index (if memorized) might be selected again. Later one still does not work well for me.
The important thing is that, with these to workarounds (using an alternate master-detail pattern and refreshing with new collection object & deselecting items) the data-virtualization will not be broken.
Remarks
Out of all virtualization solutions, which I tried while dealing with these problems I think the AlphaChi solution is the best.
WPF is definitely not build with data virtualization in mind. Its succesor UWP on the other hand is, it even has an own interface for data virtualization. Because I don't have any UWP project I could not try out myself, but I guess it would make a lot of fun. That having said, UWP does not have a native DataGrid
, so the data-virtualized collections have to be fed to Lists
or third-party DataGrids
. So there a tradeoff is needed as well.