From abb222968caf5651f6cdc256082704ebb4fd3aca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Herceg?= Date: Thu, 28 Sep 2023 17:48:08 +0200 Subject: [PATCH 1/2] Fxied bug in ExtractGenericArgumentDataContextChangeAttribute --- .../ExtractGenericArgumentDataContextChangeAttribute.cs | 4 +++- src/Framework/Framework/Utils/ReflectionUtils.cs | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Framework/Framework/Binding/ExtractGenericArgumentDataContextChangeAttribute.cs b/src/Framework/Framework/Binding/ExtractGenericArgumentDataContextChangeAttribute.cs index f81f7bb32e..69e49bbb35 100644 --- a/src/Framework/Framework/Binding/ExtractGenericArgumentDataContextChangeAttribute.cs +++ b/src/Framework/Framework/Binding/ExtractGenericArgumentDataContextChangeAttribute.cs @@ -45,7 +45,9 @@ public ExtractGenericArgumentDataContextChangeAttribute(Type genericType, int ty public override Type? GetChildDataContextType(Type dataContext, DataContextStack controlContextStack, DotvvmBindableObject control, DotvvmProperty? property = null) { - var implementations = ReflectionUtils.GetBaseTypesAndInterfaces(dataContext).ToList(); + var implementations = ReflectionUtils.GetBaseTypesAndInterfaces(dataContext) + .Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == GenericType) + .ToList(); if (implementations.Count == 0) { throw new Exception($"The data context {dataContext} doesn't implement {GenericType}!"); diff --git a/src/Framework/Framework/Utils/ReflectionUtils.cs b/src/Framework/Framework/Utils/ReflectionUtils.cs index 9af973509f..1b26d35c02 100644 --- a/src/Framework/Framework/Utils/ReflectionUtils.cs +++ b/src/Framework/Framework/Utils/ReflectionUtils.cs @@ -647,6 +647,7 @@ public static IEnumerable GetBaseTypesAndInterfaces(Type type) yield return i; } + yield return type; while (type.BaseType is { } baseType) { yield return baseType; From 57442c4dcc5599c2aa9d85d04619924bbd3f4b1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Herceg?= Date: Fri, 29 Sep 2023 16:55:10 +0200 Subject: [PATCH 2/2] Tests added --- .../ControlWithOverriddenRules.cs | 14 ++++++++ .../DefaultControlTreeResolverTests.cs | 32 ++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/Tests/Runtime/ControlTree/DefaultControlTreeResolver/ControlWithOverriddenRules.cs b/src/Tests/Runtime/ControlTree/DefaultControlTreeResolver/ControlWithOverriddenRules.cs index 605e6b65ee..998add2737 100644 --- a/src/Tests/Runtime/ControlTree/DefaultControlTreeResolver/ControlWithOverriddenRules.cs +++ b/src/Tests/Runtime/ControlTree/DefaultControlTreeResolver/ControlWithOverriddenRules.cs @@ -36,6 +36,20 @@ public string Text } public static readonly DotvvmProperty TextProperty = DotvvmProperty.Register(c => c.Text, null); + + [ExtractGenericArgumentDataContextChange(typeof(List<>), 0)] + public string Text2 + { + get { return (string)GetValue(Text2Property); } + set { SetValue(Text2Property, value); } + } + public static readonly DotvvmProperty Text2Property + = DotvvmProperty.Register(c => c.Text2, null); + + } + + public class ListOfString : List + { } } diff --git a/src/Tests/Runtime/ControlTree/DefaultControlTreeResolver/DefaultControlTreeResolverTests.cs b/src/Tests/Runtime/ControlTree/DefaultControlTreeResolver/DefaultControlTreeResolverTests.cs index 9f31cde1b8..6bd475a3ff 100644 --- a/src/Tests/Runtime/ControlTree/DefaultControlTreeResolver/DefaultControlTreeResolverTests.cs +++ b/src/Tests/Runtime/ControlTree/DefaultControlTreeResolver/DefaultControlTreeResolverTests.cs @@ -668,7 +668,7 @@ public void ResolvedTree_CustomBindingResolverInDataContext() } [TestMethod] - public void ResolvedTree_DataContextChange_ExtractGenericArgument() + public void ResolvedTree_DataContextChange_ExtractGenericArgument_Interface() { var prop = ControlWithExtractGenericArgument.TextProperty; @@ -682,6 +682,36 @@ public void ResolvedTree_DataContextChange_ExtractGenericArgument() Assert.AreEqual(typeof(List), binding.Binding.DataContextTypeStack.Parent!.DataContextType); } + [TestMethod] + public void ResolvedTree_DataContextChange_ExtractGenericArgument_Self() + { + var prop = ControlWithExtractGenericArgument.Text2Property; + + var root = ParseSource(@"@viewModel System.Collections.Generic.List +"); + + var binding = root.Content.Single().Properties[prop] as ResolvedPropertyBinding; + Assert.IsNotNull(binding); + + Assert.AreEqual(typeof(string), binding.Binding.DataContextTypeStack.DataContextType); + Assert.AreEqual(typeof(List), binding.Binding.DataContextTypeStack.Parent!.DataContextType); + } + + [TestMethod] + public void ResolvedTree_DataContextChange_ExtractGenericArgument_BaseType() + { + var prop = ControlWithExtractGenericArgument.Text2Property; + + var root = ParseSource(@"@viewModel DotVVM.Framework.Tests.Runtime.ControlTree.DefaultControlTreeResolver.ListOfString +"); + + var binding = root.Content.Single().Properties[prop] as ResolvedPropertyBinding; + Assert.IsNotNull(binding); + + Assert.AreEqual(typeof(string), binding.Binding.DataContextTypeStack.DataContextType); + Assert.AreEqual(typeof(ListOfString), binding.Binding.DataContextTypeStack.Parent!.DataContextType); + } + [TestMethod] public void DefaultViewCompiler_ControlUsageValidator() {