Your Privacy Matters: We use our own and third-party cookies to improve your experience on our website. By continuing to use the website we understand that you accept their use. Cookie Policy
400
performance of hierarchical grid when large number of rows in child bands
posted

Hello,

I have a hierarchical grid with 6 bands.  The binding source is using a BindingList.  The object type in the BindingList has one property that is also a BindingList for the child band.  Unfortunately, the binding list in the 6th band may possibly have up to 30000 objects.  I have implemented a BindingList that maintains an Index cache to solve the IndexOf bottleneck that occurs for BindingLists with a large number of objects in it.  Now the performance bottleneck is the CurrencyManager which basically performs a ResetBinding on a child bindinglist whenever it sees that the parent Current object has changed.

I will go into more detail but basically I am looking for suggestions on how to workaround this issue and maximize performance when a large number of objects in a 6th band binding list are modified.

In the case I am discussing I am modifying a property of each object in a child binding list when a parent property is changed.  The editing is done from the grid so the row I am editing is Current.  Band 0 only has one row in it, so essentially, if I modify one column in the Band 0 business object, this calls a method for event AfterRowUpdate where I modify a property on every object in Band 5.

All of my objects implement INotifyPropertyChanged and a ListChanged event on a child bindinglist will generate a property changed event for the parent business object.  This is because my parent objects show aggregated values from the child objects.  I am not using the calculator because that would slow things down a lot.  So this is why my parent objects generate a property changed event when the child binding list has changed.

Now everything is fine up until the property changed event is fired on the band 0 object.  The BindingList generates a ListChanged.ItemChanged event for the object and the BindingSource interprets this as meaning the entire object changed and therefore the child binding list property must also have changed.  It calls InnerList_ListChanged The currency manager generates a OnCurrentItemChanged (because that object is the current item) and this calls ParentCurrencyManager_CurrentItemChanged.   This is called recursively down to every current item in the 6 bands doing a ResetBinding on every current bindinglist.

Using a profiler, the ParentCurrencyManager_CurrentItemChanged consists of 96.5% of the time required to do the update.  The path to this callback delegate cannot be turned off by changing any flag such as RaiseListChangedEvents. 

I consider it a flaw that changing one property of the Current object triggers the CurrencyManager to call SetList for the DataMember property of the child list.  I wish it could use the property descriptor supplied in the ListChanged.ItemChanged event args and only call SetList for the child bindinglist if the DataMember for the child list was the property that was changed.  Assuming that every property of an object changed when the ListChanged.ItemChanged event is generated basically means that modifying one property of a parent current object invalidates the child lists and if those lists are large then the performance hit is significant.

To update 2870 objects in band 6 took 57 seconds but 55 seconds of this time was just handling the ParentCurrencyManager_CurrentItemChanged code which does absolutely nothing in my case because none of the lists changed, only the contents of one object in the list and this does not require a ResetBindings on the list.

Looking for any suggestions.  Only thing that comes to mind is subclassing the CurrencyManager or disabling the property change triggering in my own function that updates these objects and then just doing something else to inform the grid that the business object has changed.  The problem is that the listchanged.itemchanged event is informing the grid that that row has changed but its also cause the Currency manager to go through a code path that is wasting too much time doing something completely unnecessary. 

Just one more note.  I never change a binding list property, only the contents of the binding lists so the fact the currency manager resets the bindings on these lists is unnecessary but I am not sure how to avoid it.  Thanks in advance for any advice.  I am using Infragistics 8.2 but the same issue would occur if using a later version.

Here is a screenshot of the profiler call tree:

Parents
  • 400
    Offline posted

    After I wrote this.  I took advantage of an interface I added to all my business objects that basically suspends OnPropertyChanged from generating the events until I call a method to resume then.  Resuming generates a single PropertyChanged event if any where suspended. 

    This reduced multiple property change events from the parent object every time the child binding list generated a listchanged.itemchanged event to a single property changed event.  So ParentCurrencyManager_CurrentItemChanged was called 42 times instead of 3000 times.

    However, I would still have an issue for other grids I have where the last band is populated from shared object updated in a separate model.  I have an observable collection for my model and the objects in that model populate band 6.  A different code path may update any objects in that model and that update path does not know who the parent object is for any binding lists that may have a reference to the object in the observable collection. 

    So my question in previous post is still worth asking.  How to use a Currency manager in an efficient way.  Perhaps a way that doesn't assume that the child binding list changed when it received an item changed event. 

Reply Children