We are doing some performance testing on the XamGrid.
If I take a basic (no custom layouts) XamGrid and load it with 50,000 rows of really simple, flat data (1 column of random, evenly distributed short string values), then select the first row, and shift-select the last row, it takes close to a minute for the grid to finish the selection process (even though only 10-15 records are visible at a time). Debugging shows that the grid is searching some sort of internal array of the grid contents for every selected item individually, meaning 1,250,000,000 search comparisons (50,000 * 50,000 / 2, hence the time!). Changes to RecordContainerGenerationMode and numerous other properties don't seem to get around this.
Is there a design issue in the selection code by chance? Can you tell me if there is a way to avoid these cycles?
Here is your (obfuscated) call stack taken from a break while the selection process is running (Main Thread):
mscorlib.dll!System.Array.IndexOf(System.Array array, object value = {DataRecord- 18789 Value: Test Item 14130}, int startIndex, int count) + 0xdd bytes mscorlib.dll!System.Collections.ArrayList.IndexOf(object value) + 0x10 bytes Infragistics3.Windows.DataPresenter.v7.1.dll!Infragistics.Windows.DataPresenter.SelectedRecordCollection.a(Infragistics.Windows.DataPresenter.Record A_0 = {DataRecord- 18789 Value: Test Item 14130}, bool A_1 = true) + 0x71 bytes Infragistics3.Windows.DataPresenter.v7.1.dll!Infragistics.Windows.DataPresenter.SelectedRecordCollection.b(Infragistics.Windows.DataPresenter.Record A_0 = {DataRecord- 18789 Value: Test Item 14130}) + 0x21 bytes Infragistics3.Windows.DataPresenter.v7.1.dll!Infragistics.Windows.DataPresenter.DataPresenterBase.a(bool A_0 = true, Infragistics.Windows.DataPresenter.DataPresenterBase.RangeSelectionEvaluator A_1 = {Infragistics.Windows.DataPresenter.DataPresenterBase.RangeSelectionEvaluator}) + 0x22b bytes Infragistics3.Windows.DataPresenter.v7.1.dll!Infragistics.Windows.DataPresenter.DataPresenterBase.a(Infragistics.Windows.DataPresenter.Record A_0 = {DataRecord- 49999 Value: Test Item 6720}, Infragistics.Windows.DataPresenter.DataPresenterBase.SelectedItemHolder A_1 = {Infragistics.Windows.DataPresenter.DataPresenterBase.SelectedItemHolder}, bool A_2 = true, bool A_3 = true) + 0x151 bytes Infragistics3.Windows.DataPresenter.v7.1.dll!Infragistics.Windows.DataPresenter.DataPresenterBase.a(Infragistics.Windows.Selection.ISelectableItem A_0 = {DataRecord- 49999 Value: Test Item 6720}, bool A_1 = true, bool A_2 = true) + 0xf7 bytes Infragistics3.Windows.DataPresenter.v7.1.dll!Infragistics.Windows.DataPresenter.DataPresenterBase.d(Infragistics.Windows.Selection.ISelectableItem A_0 = {DataRecord- 49999 Value: Test Item 6720}, bool A_1 = true, bool A_2 = true) + 0x4d bytes Infragistics3.Windows.DataPresenter.v7.1.dll!Infragistics.Windows.DataPresenter.DataPresenterBase.Infragistics.Windows.Selection.ISelectionHost.SelectRange(Infragistics.Windows.Selection.ISelectableItem item = {DataRecord- 49999 Value: Test Item 6720}, bool clearExistingSelection = true) + 0x4b bytes Infragistics3.Windows.v7.1.dll!Infragistics.Windows.Selection.SelectionStrategyExtended.ProcessMouseLeftButtonDown(Infragistics.Windows.Selection.ISelectableItem item = {DataRecord- 49999 Value: Test Item 6720}, System.Windows.Input.MouseEventArgs e = {System.Windows.Input.MouseButtonEventArgs}, bool forceDrag = false) + 0x857 bytes Infragistics3.Windows.v7.1.dll!Infragistics.Windows.Selection.SelectionStrategyExtended.OnMouseLeftButtonDown(Infragistics.Windows.Selection.ISelectableItem item = {DataRecord- 49999 Value: Test Item 6720}, System.Windows.Input.MouseEventArgs e = {System.Windows.Input.MouseButtonEventArgs}) + 0x27 bytes Infragistics3.Windows.v7.1.dll!Infragistics.Windows.Selection.SelectionController.a(System.Windows.Input.MouseButtonEventArgs A_0 = {System.Windows.Input.MouseButtonEventArgs}) + 0x137 bytes Infragistics3.Windows.v7.1.dll!Infragistics.Windows.Controls.IGControlBase.OnMouseLeftButtonDown(System.Windows.Input.MouseButtonEventArgs e = {System.Windows.Input.MouseButtonEventArgs}) + 0x5f bytes PresentationCore.dll!System.Windows.UIElement.OnMouseLeftButtonDownThunk(object sender, System.Windows.Input.MouseButtonEventArgs e) + 0x6c bytes PresentationCore.dll!System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(System.Delegate genericHandler, object genericTarget) + 0x31 bytes PresentationCore.dll!System.Windows.RoutedEventArgs.InvokeHandler(System.Delegate handler, object target) + 0x27 bytes PresentationCore.dll!System.Windows.RoutedEventHandlerInfo.InvokeHandler(object target, System.Windows.RoutedEventArgs routedEventArgs) + 0x68 bytes PresentationCore.dll!System.Windows.EventRoute.InvokeHandlersImpl(object source = {Infragistics.Windows.DataPresenter.XamDataGrid}, System.Windows.RoutedEventArgs args = {System.Windows.Input.MouseButtonEventArgs}, bool reRaised = true) + 0x10f bytes PresentationCore.dll!System.Windows.UIElement.ReRaiseEventAs(System.Windows.RoutedEventArgs args = {System.Windows.Input.MouseButtonEventArgs}, System.Windows.RoutedEvent newEvent) + 0x156 bytes PresentationCore.dll!System.Windows.UIElement.OnMouseDownThunk(object sender, System.Windows.Input.MouseButtonEventArgs e) + 0xc2 bytes PresentationCore.dll!System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(System.Delegate genericHandler, object genericTarget) + 0x31 bytes PresentationCore.dll!System.Windows.RoutedEventArgs.InvokeHandler(System.Delegate handler, object target) + 0x27 bytes PresentationCore.dll!System.Windows.RoutedEventHandlerInfo.InvokeHandler(object target, System.Windows.RoutedEventArgs routedEventArgs) + 0x68 bytes PresentationCore.dll!System.Windows.EventRoute.InvokeHandlersImpl(object source = {System.Windows.Shapes.Rectangle}, System.Windows.RoutedEventArgs args = {System.Windows.Input.MouseButtonEventArgs}, bool reRaised = false) + 0x10f bytes PresentationCore.dll!System.Windows.UIElement.RaiseEventImpl(System.Windows.RoutedEventArgs args = {System.Windows.Input.MouseButtonEventArgs}) + 0xa2 bytes PresentationCore.dll!System.Windows.UIElement.RaiseEvent(System.Windows.RoutedEventArgs args = {System.Windows.Input.MouseButtonEventArgs}, bool trusted) + 0x43 bytes PresentationCore.dll!System.Windows.Input.InputManager.ProcessStagingArea() + 0x200 bytes PresentationCore.dll!System.Windows.Input.InputManager.ProcessInput(System.Windows.Input.InputEventArgs input) + 0x5e bytes PresentationCore.dll!System.Windows.Input.InputProviderSite.ReportInput(System.Windows.Input.InputReport inputReport) + 0x64 bytes PresentationCore.dll!System.Windows.Interop.HwndMouseInputProvider.ReportInput(System.IntPtr hwnd, System.Windows.Input.InputMode mode, int timestamp, System.Windows.Input.RawMouseActions actions, int x, int y, int wheel) + 0x32e bytes PresentationCore.dll!System.Windows.Interop.HwndMouseInputProvider.FilterMessage(System.IntPtr hwnd, int msg = 513, System.IntPtr wParam = 5, System.IntPtr lParam = 25362455, ref bool handled = false) + 0x209 bytes PresentationCore.dll!System.Windows.Interop.HwndSource.InputFilterMessage(System.IntPtr hwnd = 1443180, int msg = 513, System.IntPtr wParam = 5, System.IntPtr lParam = 25362455, ref bool handled = false) + 0x76 bytes WindowsBase.dll!MS.Win32.HwndWrapper.WndProc(System.IntPtr hwnd = 1443180, int msg = 513, System.IntPtr wParam = 5, System.IntPtr lParam = 25362455, ref bool handled = false) + 0x87 bytes WindowsBase.dll!MS.Win32.HwndSubclass.DispatcherCallbackOperation(object o) + 0x62 bytes WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate callback = {Method = {System.Object DispatcherCallbackOperation(System.Object)}}, object args = {MS.Win32.HwndSubclass.DispatcherOperationCallbackParameter}, bool isSingleParameter = true) + 0x4a bytes WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.TryCatchWhen(object source = {System.Windows.Threading.Dispatcher}, System.Delegate callback, object args, bool isSingleParameter, System.Delegate catchHandler = null) + 0x3f bytes WindowsBase.dll!System.Windows.Threading.Dispatcher.InvokeImpl(System.Windows.Threading.DispatcherPriority priority, System.TimeSpan timeout, System.Delegate method, object args, bool isSingleParameter) + 0x14f bytes WindowsBase.dll!System.Windows.Threading.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority priority, System.Delegate method, object arg) + 0x3d bytes > WindowsBase.dll!MS.Win32.HwndSubclass.SubclassWndProc(System.IntPtr hwnd = 1443180, int msg = 513, System.IntPtr wParam = 5, System.IntPtr lParam = 25362455) + 0x1e0 bytes
Yes, that's correct. In Landau terms (see http://en.wikipedia.org/wiki/Big_O_notation) it tracks right on to O = n^2 where n = # of items selected (not items in the grid), suggesting a perfectly nested loop (which presents in the stack above).
Do you have an estimated release on a fix?
Hi Matt,
First of all thanks for your feedback - we like to be made aware of such issues.
This particular issue is known to us and we are working on resolving it. Selection is slow when selecting a lot of records however it's not dependent on amount of data or records that are in the data grid. It's dependent on number of records being selected. So it should be fairly quick selecting a small number of records, like 1000 for example, regardless of amount of data in the control.
Sandip