Skip to content

Commit f487d92

Browse files
committed
Add partial generation for OnPropertyChanging/Changed
1 parent df3b529 commit f487d92

File tree

2 files changed

+59
-7
lines changed

2 files changed

+59
-7
lines changed

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

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ public static PropertyInfo GetInfo(IFieldSymbol fieldSymbol, out ImmutableArray<
142142
/// </summary>
143143
/// <param name="propertyInfo">The input <see cref="PropertyInfo"/> instance to process.</param>
144144
/// <returns>The generated <see cref="MemberDeclarationSyntax"/> instance for <paramref name="propertyInfo"/>.</returns>
145-
public static MemberDeclarationSyntax GetSyntax(PropertyInfo propertyInfo)
145+
public static MemberDeclarationSyntax GetPropertySyntax(PropertyInfo propertyInfo)
146146
{
147147
ImmutableArray<StatementSyntax>.Builder setterStatements = ImmutableArray.CreateBuilder<StatementSyntax>();
148148

@@ -292,6 +292,57 @@ public static MemberDeclarationSyntax GetSyntax(PropertyInfo propertyInfo)
292292
.WithBody(Block(setterIfStatement)));
293293
}
294294

295+
/// <summary>
296+
/// Gets the <see cref="MemberDeclarationSyntax"/> instances for the <c>OnPropertyChanging</c> and <c>OnPropertyChanged</c> methods for the input field.
297+
/// </summary>
298+
/// <param name="propertyInfo">The input <see cref="PropertyInfo"/> instance to process.</param>
299+
/// <returns>The generated <see cref="MemberDeclarationSyntax"/> instances for the <c>OnPropertyChanging</c> and <c>OnPropertyChanged</c> methods.</returns>
300+
public static ImmutableArray<MemberDeclarationSyntax> GetOnPropertyChangeMethodsSyntax(PropertyInfo propertyInfo)
301+
{
302+
// Get the parameter type syntax (adding the nullability annotation, if needed)
303+
TypeSyntax parameterType = propertyInfo.IsNullableReferenceType
304+
? NullableType(IdentifierName(propertyInfo.TypeName))
305+
: IdentifierName(propertyInfo.TypeName);
306+
307+
// Construct the generated method as follows:
308+
//
309+
// /// <summary>Executes the logic for when <see cref="<PROPERTY_NAME>"/> is changing.</summary>
310+
// [global::System.CodeDom.Compiler.GeneratedCode("...", "...")]
311+
// partial void On<PROPERTY_NAME>Changing(<PROPERTY_TYPE> value);
312+
MemberDeclarationSyntax onPropertyChangingDeclaration =
313+
MethodDeclaration(PredefinedType(Token(SyntaxKind.VoidKeyword)), Identifier($"On{propertyInfo.PropertyName}Changing"))
314+
.AddModifiers(Token(SyntaxKind.PartialKeyword))
315+
.AddParameterListParameters(Parameter(Identifier("value")).WithType(parameterType))
316+
.AddAttributeLists(
317+
AttributeList(SingletonSeparatedList(
318+
Attribute(IdentifierName("global::System.CodeDom.Compiler.GeneratedCode"))
319+
.AddArgumentListArguments(
320+
AttributeArgument(LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(typeof(ICommandGenerator).FullName))),
321+
AttributeArgument(LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(typeof(ICommandGenerator).Assembly.GetName().Version.ToString()))))))
322+
.WithOpenBracketToken(Token(TriviaList(Comment($"/// <summary>Executes the logic for when <see cref=\"{propertyInfo.PropertyName}\"/> is changing.</summary>")), SyntaxKind.OpenBracketToken, TriviaList())))
323+
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken));
324+
325+
// Construct the generated method as follows:
326+
//
327+
// /// <summary>Executes the logic for when <see cref="<PROPERTY_NAME>"/> ust changed.</summary>
328+
// [global::System.CodeDom.Compiler.GeneratedCode("...", "...")]
329+
// partial void On<PROPERTY_NAME>Changed(<PROPERTY_TYPE> value);
330+
MemberDeclarationSyntax onPropertyChangedDeclaration =
331+
MethodDeclaration(PredefinedType(Token(SyntaxKind.VoidKeyword)), Identifier($"On{propertyInfo.PropertyName}Changed"))
332+
.AddModifiers(Token(SyntaxKind.PartialKeyword))
333+
.AddParameterListParameters(Parameter(Identifier("value")).WithType(parameterType))
334+
.AddAttributeLists(
335+
AttributeList(SingletonSeparatedList(
336+
Attribute(IdentifierName("global::System.CodeDom.Compiler.GeneratedCode"))
337+
.AddArgumentListArguments(
338+
AttributeArgument(LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(typeof(ICommandGenerator).FullName))),
339+
AttributeArgument(LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(typeof(ICommandGenerator).Assembly.GetName().Version.ToString()))))))
340+
.WithOpenBracketToken(Token(TriviaList(Comment($"/// <summary>Executes the logic for when <see cref=\"{propertyInfo.PropertyName}\"/> just changed.</summary>")), SyntaxKind.OpenBracketToken, TriviaList())))
341+
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken));
342+
343+
return ImmutableArray.Create(onPropertyChangingDeclaration, onPropertyChangedDeclaration);
344+
}
345+
295346
/// <summary>
296347
/// Gets a <see cref="CompilationUnitSyntax"/> instance with the cached args of a specified type.
297348
/// </summary>

CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/ObservablePropertyGenerator.cs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,17 +69,18 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
6969
.GroupBy(HierarchyInfo.Comparer.Default)
7070
.WithComparers(HierarchyInfo.Comparer.Default, PropertyInfo.Comparer.Default.ForImmutableArray());
7171

72-
// Generate the requested properties
72+
// Generate the requested properties and methods
7373
context.RegisterSourceOutput(groupedPropertyInfo, static (context, item) =>
7474
{
75-
// Generate all properties for the current type
76-
ImmutableArray<MemberDeclarationSyntax> propertyDeclarations =
75+
// Generate all member declarations for the current type
76+
ImmutableArray<MemberDeclarationSyntax> memberDeclarations =
7777
item.Properties
78-
.Select(Execute.GetSyntax)
78+
.Select(Execute.GetPropertySyntax)
79+
.Concat(item.Properties.Select(Execute.GetOnPropertyChangeMethodsSyntax).SelectMany(static l => l))
7980
.ToImmutableArray();
8081

81-
// Insert all properties into the same partial type declaration
82-
CompilationUnitSyntax compilationUnit = item.Hierarchy.GetCompilationUnit(propertyDeclarations);
82+
// Insert all members into the same partial type declaration
83+
CompilationUnitSyntax compilationUnit = item.Hierarchy.GetCompilationUnit(memberDeclarations);
8384

8485
context.AddSource(
8586
hintName: $"{item.Hierarchy.FilenameHint}.cs",

0 commit comments

Comments
 (0)