Skip to content

Performance improvements - #240

Merged
symbiogenesis merged 14 commits into
mainfrom
performance-improvements
Jul 11, 2026
Merged

Performance improvements#240
symbiogenesis merged 14 commits into
mainfrom
performance-improvements

Conversation

@akgulebubekir

Copy link
Copy Markdown
Owner

I've go through the project and introduced some caching for performance improvements. In addition to that I've also improved the test coverage.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces several caching and lookup optimizations in the core DataGrid to reduce repeated allocations and expensive linear searches, and adds a suite of MAUI/xUnit tests in the sample app to improve coverage.

Changes:

  • Added caching for reflection-based property-path access and reused that for sort/filter operations.
  • Introduced item index mapping and original-items snapshot caching to avoid repeated IndexOf/enumerations during row updates and pagination.
  • Added/expanded unit tests in the sample app for converters, extensions, and collection helpers.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
Maui.DataGrid/Extensions/ReflectionExtensions.cs Adds cached property-path resolution for faster GetValueByPath.
Maui.DataGrid/DataGridRow.cs Avoids duplicate event handlers and replaces IndexOf with a cached index lookup.
Maui.DataGrid/DataGridHeaderRow.cs Avoids repeated Any() calls when building header cells and prevents duplicate handlers.
Maui.DataGrid/DataGridColumn.cs Adds a reset method to force re-resolving column data types when the source changes.
Maui.DataGrid/DataGrid.xaml.cs Adds original-items caching, item-index mapping, refactors selection cleanup, and adjusts filtering behavior to use GetValueByPath.
Maui.DataGrid/Converters/SortDataTypeConverter.cs Extends parsing to support `"N ASC
Maui.DataGrid.Sample/Tests/SortDataTest.cs Adds unit tests for SortData semantics and equality/hash behavior.
Maui.DataGrid.Sample/Tests/ReflectionExtensionsTest.cs Adds unit tests covering GetValueByPath/GetPropertyTypeByPath behavior.
Maui.DataGrid.Sample/Tests/ObservableRangeCollectionTest.cs Adds unit tests for range operations and notifications.
Maui.DataGrid.Sample/Tests/ListExtensionsTest.cs Adds unit tests for list/grid extension helpers.
Maui.DataGrid.Sample/Tests/LayoutOptionsExtensionsTest.cs Adds unit tests for layout-options alignment conversion.
Maui.DataGrid.Sample/Tests/DataGridColumnTest.cs Adds unit tests for DataGridColumn defaults and sortability detection.
Maui.DataGrid.Sample/Tests/ConvertersTest.cs Adds unit tests for converters, including new SortData parsing cases.
Maui.DataGrid.Sample/Tests/BindablePropertyExtensionsTest.cs Adds unit tests for bindable property helper behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +90 to +92
properties[i] = property;
currentType = property.PropertyType;
}
{
private const char PropertyOfOp = '.';

private static readonly ConcurrentDictionary<(Type Type, string Path), PropertyInfo[]?> PropertyPathCache = new();
Comment on lines +1225 to +1232
if (_internalItemsIndexMap == null)
{
_internalItemsIndexMap = new(InternalItems.Count);
for (var i = 0; i < InternalItems.Count; i++)
{
_internalItemsIndexMap[InternalItems[i]] = i;
}
}
Comment on lines +1268 to 1286
if (originalItems.Count == 0)
{
PageCount = 1;
_internalItemsIndexMap = null;
InternalItems.Clear();
return;
}

var filteredItems = CanFilter() ? GetFilteredItems(originalItems) : originalItems;
var filteredItems = CanFilter() ? GetFilteredItems(originalItems) : originalItems;

var sortedItems = CanSort(sortData) ? GetSortedItems(filteredItems, sortData!) : filteredItems;
var sortedItems = CanSort(sortData) ? GetSortedItems(filteredItems, sortData!) : filteredItems;

var paginatedItems = PaginationEnabled ? GetPaginatedItems(sortedItems) : sortedItems;
var paginatedItems = PaginationEnabled ? GetPaginatedItems(sortedItems) : sortedItems;

PageCount = (int)Math.Ceiling(filteredItems.Count / (double)PageSize);
PageCount = (int)Math.Ceiling(filteredItems.Count / (double)PageSize);

InternalItems.ReplaceRange(paginatedItems);
}
_internalItemsIndexMap = null;
InternalItems.ReplaceRange(paginatedItems);
}
Comment on lines +1541 to +1547
if (string.IsNullOrEmpty(column.FilterText))
{
Debug.WriteLine(ex);
return false;
return true;
}
#pragma warning restore CA1031 // Do not catch general exception types

var value = item.GetValueByPath(column.PropertyName)?.ToString();
return value?.Contains(column.FilterText, StringComparison.OrdinalIgnoreCase) == true;
@symbiogenesis

Copy link
Copy Markdown
Collaborator

Nice work. This looks good to me. I think I will do a follow-up PR to improve the thread-safety without reintroducing locks, although nothing in here is incorrect. The performance looks good, when I run it.

Found some stuff with AI, but I will clean it all up. And there's stuff I should do to make the build and tests work nicely.

@symbiogenesis
symbiogenesis merged commit d1ceeb0 into main Jul 11, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants