Skip to content

Commit e202a55

Browse files
committed
Forward all DataAnnotations attribute for [ObservableProperty]
1 parent 7efbb55 commit e202a55

File tree

2 files changed

+64
-2
lines changed

2 files changed

+64
-2
lines changed

CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/ObservablePropertyGenerator.Execute.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,19 @@ internal static class Execute
118118
continue;
119119
}
120120

121-
// Track the current validation attribute, if applicable
122-
if (attributeData.AttributeClass?.InheritsFromFullyQualifiedName("global::System.ComponentModel.DataAnnotations.ValidationAttribute") == true)
121+
// Track the current attribute for forwarding if applicable. The following attributes are special cased:
122+
// - Validation attributes (System.ComponentModel.DataAnnotations.ValidationAttribute)
123+
// - Display attributes (System.ComponentModel.DataAnnotations.DisplayAttribute)
124+
// - UI hint attributes(System.ComponentModel.DataAnnotations.UIHintAttribute)
125+
// - Scaffold column attributes (System.ComponentModel.DataAnnotations.ScaffoldColumnAttribute)
126+
// - Editable attributes (System.ComponentModel.DataAnnotations.EditableAttribute)
127+
// - Key attributes (System.ComponentModel.DataAnnotations.KeyAttribute)
128+
if (attributeData.AttributeClass?.InheritsFromFullyQualifiedName("global::System.ComponentModel.DataAnnotations.ValidationAttribute") == true ||
129+
attributeData.AttributeClass?.HasOrInheritsFromFullyQualifiedName("global::System.ComponentModel.DataAnnotations.UIHintAttribute") == true ||
130+
attributeData.AttributeClass?.HasOrInheritsFromFullyQualifiedName("global::System.ComponentModel.DataAnnotations.ScaffoldColumnAttribute") == true ||
131+
attributeData.AttributeClass?.HasFullyQualifiedName("global::System.ComponentModel.DataAnnotations.DisplayAttribute") == true ||
132+
attributeData.AttributeClass?.HasFullyQualifiedName("global::System.ComponentModel.DataAnnotations.EditableAttribute") == true ||
133+
attributeData.AttributeClass?.HasFullyQualifiedName("global::System.ComponentModel.DataAnnotations.KeyAttribute") == true)
123134
{
124135
validationAttributes.Add(AttributeInfo.From(attributeData));
125136
}

tests/CommunityToolkit.Mvvm.UnitTests/Test_ObservablePropertyAttribute.cs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,46 @@ public void Test_ObservableProperty_InheritedModelWithCommandUsingInheritedObser
658658
Assert.IsTrue(model.SaveCommand.CanExecute(null));
659659
}
660660

661+
[TestMethod]
662+
public void Test_ObservableProperty_ForwardsSpecialCasesDataAnnotationAttributes()
663+
{
664+
PropertyInfo propertyInfo = typeof(ModelWithAdditionalDataAnnotationAttributes).GetProperty(nameof(ModelWithAdditionalDataAnnotationAttributes.Name))!;
665+
666+
DisplayAttribute? displayAttribute = (DisplayAttribute?)propertyInfo.GetCustomAttribute(typeof(DisplayAttribute));
667+
668+
Assert.IsNotNull(displayAttribute);
669+
Assert.AreEqual(displayAttribute!.Name, "MyProperty");
670+
Assert.AreEqual(displayAttribute.ResourceType, typeof(List<double>));
671+
Assert.AreEqual(displayAttribute.Prompt, "Foo bar baz");
672+
673+
KeyAttribute? keyAttribute = (KeyAttribute?)propertyInfo.GetCustomAttribute(typeof(KeyAttribute));
674+
675+
Assert.IsNotNull(keyAttribute);
676+
677+
EditableAttribute? editableAttribute = (EditableAttribute?)propertyInfo.GetCustomAttribute(typeof(EditableAttribute));
678+
679+
Assert.IsNotNull(keyAttribute);
680+
Assert.IsTrue(editableAttribute!.AllowEdit);
681+
682+
UIHintAttribute? uiHintAttribute = (UIHintAttribute?)propertyInfo.GetCustomAttribute(typeof(UIHintAttribute));
683+
684+
Assert.IsNotNull(uiHintAttribute);
685+
Assert.AreEqual(uiHintAttribute!.UIHint, "MyControl");
686+
Assert.AreEqual(uiHintAttribute.PresentationLayer, "WPF");
687+
Assert.AreEqual(uiHintAttribute.ControlParameters.Count, 3);
688+
Assert.IsTrue(uiHintAttribute.ControlParameters.ContainsKey("Foo"));
689+
Assert.IsTrue(uiHintAttribute.ControlParameters.ContainsKey("Bar"));
690+
Assert.IsTrue(uiHintAttribute.ControlParameters.ContainsKey("Baz"));
691+
Assert.AreEqual(uiHintAttribute.ControlParameters["Foo"], 42);
692+
Assert.AreEqual(uiHintAttribute.ControlParameters["Bar"], 3.14);
693+
Assert.AreEqual(uiHintAttribute.ControlParameters["Baz"], "Hello");
694+
695+
ScaffoldColumnAttribute? scaffoldColumnAttribute = (ScaffoldColumnAttribute?)propertyInfo.GetCustomAttribute(typeof(ScaffoldColumnAttribute));
696+
697+
Assert.IsNotNull(scaffoldColumnAttribute);
698+
Assert.IsTrue(scaffoldColumnAttribute!.Scaffold);
699+
}
700+
661701
public abstract partial class BaseViewModel : ObservableObject
662702
{
663703
public string? Content { get; set; }
@@ -1066,4 +1106,15 @@ public override void Save()
10661106
{
10671107
}
10681108
}
1109+
1110+
public partial class ModelWithAdditionalDataAnnotationAttributes : ObservableValidator
1111+
{
1112+
[ObservableProperty]
1113+
[Display(Name = "MyProperty", ResourceType = typeof(List<double>), Prompt = "Foo bar baz")]
1114+
[Key]
1115+
[Editable(true)]
1116+
[UIHint("MyControl", "WPF", new object[] { "Foo", 42, "Bar", 3.14, "Baz", "Hello" })]
1117+
[ScaffoldColumn(true)]
1118+
private string? name;
1119+
}
10691120
}

0 commit comments

Comments
 (0)