From c538d738190a943dcef6ed6ffb60450e64f0f899 Mon Sep 17 00:00:00 2001
From: Matthew Batchelor <65035377+PlayerModu@users.noreply.github.com>
Date: Fri, 6 Mar 2026 10:11:20 +0000
Subject: [PATCH 1/2] fix(ListExtended): use ToStringFunc for ItemCollection
search on complex types (#606)
Search with ItemCollection was ignoring ToStringFunc and falling back to
Converter.Convert() for complex types, making search fail for custom display formats.
- Use ToStringFunc when available for ItemCollection search
- Add integration tests for complex type search
- Update docs with complex type example
---
.../Examples/SelectExtendedExample6.razor | 52 +++++++++++++++++++
.../ListExtended/MudListExtended.razor.cs | 12 +++--
...ListExtendedItemCollectionSearchTest.razor | 26 ++++++++++
.../Components/ListExtendedTests.cs | 45 ++++++++++++++++
4 files changed, 131 insertions(+), 4 deletions(-)
create mode 100644 tests/CodeBeam.MudBlazor.Extensions.UnitTests.Viewer/TestComponents/ListExtended/ListExtendedItemCollectionSearchTest.razor
diff --git a/docs/CodeBeam.MudBlazor.Extensions.Docs/Pages/Components/SelectExtended/Examples/SelectExtendedExample6.razor b/docs/CodeBeam.MudBlazor.Extensions.Docs/Pages/Components/SelectExtended/Examples/SelectExtendedExample6.razor
index 727793f1..ca44896c 100644
--- a/docs/CodeBeam.MudBlazor.Extensions.Docs/Pages/Components/SelectExtended/Examples/SelectExtendedExample6.razor
+++ b/docs/CodeBeam.MudBlazor.Extensions.Docs/Pages/Components/SelectExtended/Examples/SelectExtendedExample6.razor
@@ -21,11 +21,47 @@
+
+
+ Complex Type with ToStringFunc and Search
+
+
+
+
+
+
+
+ Selected House:
+ @if (_selectedHouse != null)
+ {
+ Number: @_selectedHouse.Number
+ Name: @_selectedHouse.Name
+ Postcode: @_selectedHouse.Postcode
+ }
+ else
+ {
+ None selected
+ }
+
+
+
+
@code {
bool _multiselection;
bool _searchBoxAutoFocus;
bool _searchBoxClearable;
private string? _selectedState;
+ private TestHouse? _selectedHouse;
private string[] _states =
{
@@ -45,6 +81,22 @@
"Washington", "West Virginia", "Wisconsin", "Wyoming",
};
+ private class TestHouse
+ {
+ public int Number { get; set; }
+ public string? Name { get; set; }
+ public string? Postcode { get; set; }
+ }
+
+ private List TestHouses = new()
+ {
+ new TestHouse { Number = 1, Name = "Test1", Postcode = "12345" },
+ new TestHouse { Number = 2, Name = "Test2", Postcode = "54321" },
+ new TestHouse { Number = 3, Name = "Test3", Postcode = "67890" },
+ new TestHouse { Number = 4, Name = "Test4", Postcode = "09876" },
+ new TestHouse { Number = 5, Name = "Test5", Postcode = "11223" },
+ };
+
private bool SearchItems(string value, string searchString)
{
if (searchString == "")
diff --git a/src/CodeBeam.MudBlazor.Extensions/Components/ListExtended/MudListExtended.razor.cs b/src/CodeBeam.MudBlazor.Extensions/Components/ListExtended/MudListExtended.razor.cs
index a9fb10ad..c465e73e 100644
--- a/src/CodeBeam.MudBlazor.Extensions/Components/ListExtended/MudListExtended.razor.cs
+++ b/src/CodeBeam.MudBlazor.Extensions/Components/ListExtended/MudListExtended.razor.cs
@@ -956,7 +956,7 @@ protected internal async Task SearchBoxHandleKeyDownAsync(KeyboardEventArgs obj)
await MudSelectExtended.FocusAsync();
}
break;
- case "Escape":
+ case "Escape":
if (MudSelectExtended != null && MultiSelection == false)
{
await MudSelectExtended.CloseMenu();
@@ -1783,10 +1783,14 @@ protected internal async ValueTask ScrollToMiddleAsync(MudListItemExtended?
if (SearchFunc != null)
{
- return ItemCollection.Where(x => SearchFunc.Invoke(x, _searchString)).ToList();
+ return [.. ItemCollection.Where(x => SearchFunc.Invoke(x, _searchString))];
}
- return ItemCollection.Where(x => Converter.Convert(x)?.Contains(_searchString, StringComparison.InvariantCultureIgnoreCase) == true).ToList();
+ var stringValue = new Func(x =>
+ ToStringFunc != null ? ToStringFunc(x) : Converter.Convert(x)
+ );
+
+ return [.. ItemCollection.Where(x => stringValue(x)?.Contains(_searchString, StringComparison.InvariantCultureIgnoreCase) == true)];
}
///
@@ -1834,7 +1838,7 @@ protected async Task OnDoubleClickHandler(MouseEventArgs? args, T? itemValue)
///
///
protected internal MudListItemExtended? ActiveItem => _lastActivatedItem;
-
+
///
///
///
diff --git a/tests/CodeBeam.MudBlazor.Extensions.UnitTests.Viewer/TestComponents/ListExtended/ListExtendedItemCollectionSearchTest.razor b/tests/CodeBeam.MudBlazor.Extensions.UnitTests.Viewer/TestComponents/ListExtended/ListExtendedItemCollectionSearchTest.razor
new file mode 100644
index 00000000..e1d5c1da
--- /dev/null
+++ b/tests/CodeBeam.MudBlazor.Extensions.UnitTests.Viewer/TestComponents/ListExtended/ListExtendedItemCollectionSearchTest.razor
@@ -0,0 +1,26 @@
+@namespace MudExtensions.UnitTests.TestComponents
+
+
+
+
+@code {
+ public MudListExtended? List { get; set; }
+
+ public List Houses = new()
+ {
+ new TestHouse { Number = 1, Name = "Test1", Postcode = "12345" },
+ new TestHouse { Number = 2, Name = "Test2", Postcode = "54321" },
+ new TestHouse { Number = 3, Name = "Test3", Postcode = "67890" },
+ };
+
+ public class TestHouse
+ {
+ public int Number { get; set; }
+ public string? Name { get; set; }
+ public string? Postcode { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/tests/CodeBeam.MudBlazor.Extensions.UnitTests/Components/ListExtendedTests.cs b/tests/CodeBeam.MudBlazor.Extensions.UnitTests/Components/ListExtendedTests.cs
index 60a83951..98510dfb 100644
--- a/tests/CodeBeam.MudBlazor.Extensions.UnitTests/Components/ListExtendedTests.cs
+++ b/tests/CodeBeam.MudBlazor.Extensions.UnitTests/Components/ListExtendedTests.cs
@@ -363,5 +363,50 @@ public async Task List_SearchChanged_WithNullItemCollection()
var finalItems = comp.FindAll("div.mud-list-item-extended").Count;
finalItems.Should().Be(9);
}
+
+
+ [Test]
+ public void ListExtended_Search_With_ItemCollection_Should_Use_ToStringFunc()
+ {
+ // Arrange
+ var comp = Context.Render();
+ var list = comp.FindComponent>().Instance;
+
+ list.SearchBox.Should().BeTrue();
+ list.ItemCollection.Should().HaveCount(3);
+
+ // Act - search for "1 - Test1" using reflection to set _searchString
+ var searchStringField = typeof(MudListExtended)
+ .GetField("_searchString", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
+ searchStringField?.SetValue(list, "1 - Test1");
+
+ var result = list.GetSearchedItems();
+
+ // Assert - should find item by ToStringFunc format, not class name
+ result.Should().NotBeNull();
+ result.Should().HaveCount(1);
+ result.First().Number.Should().Be(1);
+ result.First().Name.Should().Be("Test1");
+ }
+
+ [Test]
+ public void ListExtended_Search_Should_Find_Items_By_Custom_Display_Format_Not_ClassName()
+ {
+ // Arrange
+ var comp = Context.Render();
+ var list = comp.FindComponent>().Instance;
+
+ // Act - search for "Test2" (part of the formatted display, not the class name)
+ var searchStringField = typeof(MudListExtended)
+ .GetField("_searchString", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
+ searchStringField?.SetValue(list, "Test2");
+
+ var result = list.GetSearchedItems();
+
+ // Assert
+ result.Should().HaveCount(1);
+ result.First().Name.Should().Be("Test2");
+ result.First().Number.Should().Be(2);
+ }
}
}
\ No newline at end of file
From bd22cc503fa40c3c5264af4735d993de420c1bdc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mehmet=20Can=20Karag=C3=B6z?=
Date: Tue, 10 Mar 2026 10:38:57 +0300
Subject: [PATCH 2/2] Simple Docs Changes
---
.../Examples/SelectExtendedExample3.razor | 20 +++----
.../Examples/SelectExtendedExample5.razor | 54 +++++++++----------
.../Examples/SelectExtendedExample6.razor | 6 +--
.../Examples/SelectExtendedExample7.razor | 16 +++---
4 files changed, 48 insertions(+), 48 deletions(-)
diff --git a/docs/CodeBeam.MudBlazor.Extensions.Docs/Pages/Components/SelectExtended/Examples/SelectExtendedExample3.razor b/docs/CodeBeam.MudBlazor.Extensions.Docs/Pages/Components/SelectExtended/Examples/SelectExtendedExample3.razor
index 94e02a4d..d285843e 100644
--- a/docs/CodeBeam.MudBlazor.Extensions.Docs/Pages/Components/SelectExtended/Examples/SelectExtendedExample3.razor
+++ b/docs/CodeBeam.MudBlazor.Extensions.Docs/Pages/Components/SelectExtended/Examples/SelectExtendedExample3.razor
@@ -25,10 +25,10 @@
-
-
-
-
+
+
+
+
Selected Value: @_selectedValue
Selected Values: @(_selectedValues == null ? null : string.Join(", ", _selectedValues))
@@ -36,10 +36,10 @@
@code {
- bool _multiSelection = false;
- bool _sticky = true;
- bool _nested = false;
- bool _initiallyExpanded = false;
- string? _selectedValue;
- IEnumerable? _selectedValues;
+ private bool _multiSelection = false;
+ private bool _sticky = true;
+ private bool _nested = false;
+ private bool _initiallyExpanded = false;
+ private string? _selectedValue;
+ private IEnumerable? _selectedValues;
}
\ No newline at end of file
diff --git a/docs/CodeBeam.MudBlazor.Extensions.Docs/Pages/Components/SelectExtended/Examples/SelectExtendedExample5.razor b/docs/CodeBeam.MudBlazor.Extensions.Docs/Pages/Components/SelectExtended/Examples/SelectExtendedExample5.razor
index 33e18410..20beac66 100644
--- a/docs/CodeBeam.MudBlazor.Extensions.Docs/Pages/Components/SelectExtended/Examples/SelectExtendedExample5.razor
+++ b/docs/CodeBeam.MudBlazor.Extensions.Docs/Pages/Components/SelectExtended/Examples/SelectExtendedExample5.razor
@@ -10,7 +10,7 @@
}
-
@foreach (var state in states)
{
@@ -18,7 +18,7 @@
}
-
@@ -38,42 +38,42 @@
- Standard Text
- Customized Text
- Chip
+ Standard Text
+ Customized Text
+ Chip
Value:
"
- @stringValue
+ @_stringValue
"
SelectedValues: HashSet<string>
{
- @(string.Join(", ", stringValues.Select(x => $"\"{x}\"")))
- }
-
-
-
-
-
-
-
-
+ @(string.Join(", ", _stringValues.Select(x => $"\"{x}\"")))
+ }
+
+
+
+
+
+
+
+
- @code {
- MudRadioGroup? _radioGroup;
- ValuePresenter _valuePresenter = ValuePresenter.Text;
- string stringValue { get; set; } = "Nothing selected";
- IEnumerable stringValues { get; set; } = new HashSet() { "Alaska", "California" };
- int? intValue;
- IEnumerable intValues { get; set; } = new HashSet() { 2, 3 };
- bool _chipCloseable = false;
- Variant _chipVariant = Variant.Filled;
- Size _chipSize = Size.Small;
- bool _nowrap;
+@code {
+ private MudRadioGroup? _radioGroup;
+ private ValuePresenter _valuePresenter = ValuePresenter.Text;
+ private string _stringValue = "Nothing selected";
+ private IEnumerable _stringValues = new HashSet() { "Alaska", "California" };
+ private int? intValue;
+ private IEnumerable intValues { get; set; } = new HashSet() { 2, 3 };
+ private bool _chipCloseable = false;
+ private Variant _chipVariant = Variant.Filled;
+ private Size _chipSize = Size.Small;
+ private bool _nowrap;
public class Complex
{
diff --git a/docs/CodeBeam.MudBlazor.Extensions.Docs/Pages/Components/SelectExtended/Examples/SelectExtendedExample6.razor b/docs/CodeBeam.MudBlazor.Extensions.Docs/Pages/Components/SelectExtended/Examples/SelectExtendedExample6.razor
index ca44896c..b71d39d8 100644
--- a/docs/CodeBeam.MudBlazor.Extensions.Docs/Pages/Components/SelectExtended/Examples/SelectExtendedExample6.razor
+++ b/docs/CodeBeam.MudBlazor.Extensions.Docs/Pages/Components/SelectExtended/Examples/SelectExtendedExample6.razor
@@ -14,9 +14,9 @@
-
-
-
+
+
+
diff --git a/docs/CodeBeam.MudBlazor.Extensions.Docs/Pages/Components/SelectExtended/Examples/SelectExtendedExample7.razor b/docs/CodeBeam.MudBlazor.Extensions.Docs/Pages/Components/SelectExtended/Examples/SelectExtendedExample7.razor
index e3f4d973..78fe33af 100644
--- a/docs/CodeBeam.MudBlazor.Extensions.Docs/Pages/Components/SelectExtended/Examples/SelectExtendedExample7.razor
+++ b/docs/CodeBeam.MudBlazor.Extensions.Docs/Pages/Components/SelectExtended/Examples/SelectExtendedExample7.razor
@@ -12,9 +12,9 @@
- Before Search (Default)
- Start of the searchbox in the same line
- After Search
+ Before Search (Default)
+ Start of the searchbox in the same line
+ After Search
@@ -33,11 +33,11 @@
- @code {
- ValuePresenter _valuePresenter = ValuePresenter.Text;
- SelectAllPosition _selectAllPosition;
- string value { get; set; } = "Nothing selected";
- IEnumerable options { get; set; } = new HashSet() { "Alaska", "California" };
+@code {
+ private ValuePresenter _valuePresenter = ValuePresenter.Text;
+ private SelectAllPosition _selectAllPosition;
+ private string value { get; set; } = "Nothing selected";
+ private IEnumerable options { get; set; } = new HashSet() { "Alaska", "California" };
private string[] states =
{