From 4d9a9c9ac2ecff8339578e9ce8bbeececdd2ec99 Mon Sep 17 00:00:00 2001 From: Petar Slavov <89679515+PetarSlavov@users.noreply.github.com> Date: Fri, 15 Aug 2025 09:28:52 +0300 Subject: [PATCH] Add GetProperty that supports retrieval of interface properties. (#2255) * Introduces a new static method `GetProperty` in the `Radzen.PropertyAccess` class to retrieve properties by name, including support for interfaces. Updates `DropDownBase.cs` to utilize this new method, enabling property retrieval for collections of interfaces in multiselect DropDowns. * Add unit tests for property resolution in interfaces Implemented unit tests in `PropertyAccessTests.cs` to verify the resolution of `Description`, `Name`, and `Id` properties from the interfaces `ISimpleInterface`, `ISimpleNestedInterface`, and `ISimpleBaseInterface`. Defined the interfaces to support the tests for the `GetProperty` method functionality. --- Radzen.Blazor.Tests/PropertyAccessTests.cs | 38 ++++++++++++++++++++++ Radzen.Blazor/Common.cs | 26 +++++++++++++++ Radzen.Blazor/DropDownBase.cs | 6 ++-- 3 files changed, 68 insertions(+), 2 deletions(-) diff --git a/Radzen.Blazor.Tests/PropertyAccessTests.cs b/Radzen.Blazor.Tests/PropertyAccessTests.cs index 727aa2b8..fc05575c 100644 --- a/Radzen.Blazor.Tests/PropertyAccessTests.cs +++ b/Radzen.Blazor.Tests/PropertyAccessTests.cs @@ -113,5 +113,43 @@ namespace Radzen.Blazor.Tests { public List Values { get; set; } } + + [Fact] + public void GetProperty_Should_Resolve_DescriptionProperty() + { + var descriptionProperty = PropertyAccess.GetProperty(typeof(ISimpleInterface), nameof(ISimpleInterface.Description)); + + Assert.NotNull(descriptionProperty); + } + + [Fact] + public void GetProperty_Should_Resolve_NameProperty() + { + var nameProperty = PropertyAccess.GetProperty(typeof(ISimpleInterface), nameof(ISimpleInterface.Name)); + + Assert.NotNull(nameProperty); + } + + [Fact] + public void GetProperty_Should_Resolve_IdProperty() + { + var idProperty = PropertyAccess.GetProperty(typeof(ISimpleInterface), nameof(ISimpleBaseInterface.Id)); + Assert.NotNull(idProperty); + } + + interface ISimpleInterface : ISimpleNestedInterface + { + string Description { get; set; } + } + + interface ISimpleNestedInterface : ISimpleBaseInterface + { + string Name { get; set; } + } + + interface ISimpleBaseInterface + { + int Id { get; set; } + } } } diff --git a/Radzen.Blazor/Common.cs b/Radzen.Blazor/Common.cs index c6cd80f9..94a752e4 100644 --- a/Radzen.Blazor/Common.cs +++ b/Radzen.Blazor/Common.cs @@ -3498,6 +3498,32 @@ namespace Radzen return null; } + /// + /// Gets the property by its name. If the type is an interface, it will search through all interfaces implemented by the type. + /// + /// The type. + /// The property. + /// PropertyInfo. + public static PropertyInfo GetProperty(Type type, string property) + { + if (type.IsInterface) + { + var interfaces = type.GetInterfaces(); + + foreach (var @interface in interfaces) + { + var propertyInfo = @interface.GetProperty(property); + + if (propertyInfo != null) + { + return propertyInfo; + } + } + } + + return type.GetProperty(property); + } + /// /// Gets the dynamic property expression when binding to IDictionary. /// diff --git a/Radzen.Blazor/DropDownBase.cs b/Radzen.Blazor/DropDownBase.cs index ec47a904..13532a0e 100644 --- a/Radzen.Blazor/DropDownBase.cs +++ b/Radzen.Blazor/DropDownBase.cs @@ -318,7 +318,8 @@ namespace Radzen if (!string.IsNullOrEmpty(ValueProperty)) { - System.Reflection.PropertyInfo pi = PropertyAccess.GetElementType(Data.GetType()).GetProperty(ValueProperty); + var elementType = PropertyAccess.GetElementType(Data.GetType()); + System.Reflection.PropertyInfo pi = PropertyAccess.GetProperty(elementType, ValueProperty); internalValue = selectedItems.Select(i => GetItemOrValueFromProperty(i, ValueProperty)).AsQueryable().Cast(pi.PropertyType); } else @@ -1167,7 +1168,8 @@ namespace Radzen if (!string.IsNullOrEmpty(ValueProperty)) { - System.Reflection.PropertyInfo pi = PropertyAccess.GetElementType(Data.GetType()).GetProperty(ValueProperty); + var elementType = PropertyAccess.GetElementType(Data.GetType()); + System.Reflection.PropertyInfo pi = PropertyAccess.GetProperty(elementType, ValueProperty); internalValue = selectedItems.Select(i => GetItemOrValueFromProperty(i, ValueProperty)).AsQueryable().Cast(pi.PropertyType); } else