Hello,
I have several use-cases for a grid bound to a large number of rows (10k+) that also needs to keep track of the value history for a couple of fields. This is also a live dataset which receives regular updates.
I am currently using the CellDataPresenter ValueHistory collection to keep track of changes on a column but I am running into several issues with regards to memory use. I need to store the history values of rows that aren't displayed in the scrolling region so I currently have the following settings for the grid:
<igdp:XamDataGrid CellContainerGenerationMode="PreLoad" RecordContainerGenerationMode="PreLoad">
And my field settings are
<igdp:UnboundField Label="Change" Name="Change" BindingMode="OneWay" BindingPath="[PriceMove]" DataType="{x:Type System:Double}" BindingRetentionMode="Retain" > <igdp:UnboundField.Settings> <igdp:FieldSettings DataValueChangedHistoryLimit="2" DataValueChangedScope="AllAllocatedRecords" DataValueChangedNotificationsActive="True" CellValuePresenterStyle="{StaticResource staleCellStyle}" /> </igdp:UnboundField.Settings> </igdp:UnboundField>
The style staleCellStyle is using a converter to access the cell value history and do its magic.
My question is the following:
Can I still use some virtualization features of the grid if I want to use full-grid history support? Can I virtualize the cells but not the records? I am slightly confused by the record / cell virtualization strategies here.
Also, I noticed that without binding retention set to Retain, the grid would sometimes not process the PropertyChanged events while scrolling, and the bindings would just get recreated after the event had fired, thus missing any updates that occured during scrolling - although the updates to the dataset are done on the UI thread.
Thanks for your help,
Florian
Florian Doyon said: <igdp:XamDataGrid CellContainerGenerationMode="PreLoad" RecordContainerGenerationMode="PreLoad">
I would not use these settings with any except a grid that will only have a small number of records. These settings relate to what elements (containers) are created and how long they are retained. RecordContainerGenerationMode is used by the GridViewPanel to determine which recordpresenters should be allocated. The CellContainerGenerationMode is used to determine which CellValuePresenter, etc. elements should be allocated. For both of these it is recommended that you continue to use the recycling/virtualize options so that only the elements that are needed for what is in view are created/maintained.
Florian Doyon said:Can I still use some virtualization features of the grid if I want to use full-grid history support?
Yes you can use the virtualization features. I'm guessing the issue you are facing relates to the fact that the grid does not pre-allocate records by default - it lazily allocates them as they are needed. So if you are expecting the history to be maintained for every record - even those that you or the grid have never accessed - then you would probably want to set the RecordLoadMode to PreloadRecords. Since the cells are also lazily allocated, you would want to handle the InitializeRecord event and simply index into the Cells collection of the e.Record for the Field on which you have enabled the history.
Florian Doyon said:Can I virtualize the cells but not the records?
In theory one can set those properties such that the recordpresenters are pre/lazy loaded but that the cellvaluepresenters are still recycled but I would still recommend against preloading the record presenters if you have more than a handful of records since WPF does have limits on the number of elements used.
Florian Doyon said: Also, I noticed that without binding retention set to Retain, the grid would sometimes not process the PropertyChanged events while scrolling, and the bindings would just get recreated after the event had fired, thus missing any updates that occured during scrolling - although the updates to the dataset are done on the UI thread.
This is correct. As documented for that property, the bindings for unbound cells are only kept around while they are needed and then discarded. Since they are not needed in this case for the records out of view (e.g. because there are no cellvaluepresenters accessing them, no summaries on them, etc), the bindings will be released. Since the bindings are released the grid won't get the change notifications and the history won't be updated.
Hey Guys,
I apologize for bringing up an old issue but I'm experiencing this as well. I'm using the cell value history to indicate edited cells. When I bulk edit 19 + records, only the records in the scroll view log the value change in the history.
As per your above suggestion, I expect my grid to have 100s of records so I tried setting RecordLoadMode="PreloadRecords" and running the following in my InitializeRecord handler to try and initialize each cell:
if (e.Record == null || !e.Record.IsDataRecord || e.Record as DataRecord == null) return; (e.Record as DataRecord).Cells.ForEach(cell => {});
I'm not sure if this is what you meant by "Since the cells are also lazily allocated, you would want to handle the InitializeRecord event and simply index into the Cells collection of the e.Record for the Field on which you have enabled the history" but this is not working for me.
Using CellContainerGenerationMode="PreLoad" & RecordContainerGenerationMode="PreLoad" but affects my screen's performance (as expected). Do you have any other suggestions?
Sorry for the spam but I just found a solution to my issue. I just needed to set the DataValueChangedScope in the FieldSettings to AllAllocatedRecords. I hope this helps others!