Skip to content

Commit 98af5a9

Browse files
committed
Add INotifyPropertyChanged implementation to Builder classes
Fixes #78
1 parent a9b40bc commit 98af5a9

1 file changed

Lines changed: 57 additions & 1 deletion

File tree

src/ImmutableObjectGraph.Generation/CodeGen+BuilderGen.cs

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ protected class BuilderGen : FeatureGenerator
2626
private static readonly IdentifierNameSyntax ToImmutableMethodName = SyntaxFactory.IdentifierName("ToImmutable");
2727
private static readonly IdentifierNameSyntax CreateBuilderMethodName = SyntaxFactory.IdentifierName("CreateBuilder");
2828
private static readonly IdentifierNameSyntax ImmutableFieldName = SyntaxFactory.IdentifierName("immutable");
29+
private static readonly TypeSyntax INotifyPropertyChanged = SyntaxFactory.ParseTypeName("System.ComponentModel.INotifyPropertyChanged");
30+
private static readonly IdentifierNameSyntax OnPropertyChangedMethodName = SyntaxFactory.IdentifierName("OnPropertyChanged");
2931

3032
public BuilderGen(CodeGen generator)
3133
: base(generator)
@@ -52,10 +54,13 @@ protected override void GenerateCore()
5254
builderMembers.Add(this.CreateConstructor());
5355
builderMembers.AddRange(this.CreateMutableProperties());
5456
builderMembers.Add(this.CreateToImmutableMethod());
57+
builderMembers.Add(this.CreatePropertyChangedEvent());
58+
builderMembers.Add(this.CreateOnPropertyChangedMethod());
5559
var builderType = SyntaxFactory.ClassDeclaration(BuilderTypeName.Identifier)
5660
.AddModifiers(
5761
SyntaxFactory.Token(SyntaxKind.PublicKeyword),
5862
SyntaxFactory.Token(SyntaxKind.PartialKeyword))
63+
.AddBaseListTypes(SyntaxFactory.SimpleBaseType(INotifyPropertyChanged))
5964
.WithMembers(SyntaxFactory.List(builderMembers));
6065
if (this.generator.applyToMetaType.HasAncestor)
6166
{
@@ -206,7 +211,13 @@ protected IReadOnlyList<MemberDeclarationSyntax> CreateMutableProperties()
206211
SyntaxFactory.ExpressionStatement(SyntaxFactory.AssignmentExpression(
207212
SyntaxKind.SimpleAssignmentExpression,
208213
thisField,
209-
SyntaxFactory.IdentifierName("value"))));
214+
SyntaxFactory.IdentifierName("value"))),
215+
SyntaxFactory.ExpressionStatement(
216+
SyntaxFactory.InvocationExpression(
217+
SyntaxFactory.MemberAccessExpression(
218+
SyntaxKind.SimpleMemberAccessExpression,
219+
SyntaxFactory.ThisExpression(),
220+
OnPropertyChangedMethodName))));
210221

211222
var property = SyntaxFactory.PropertyDeclaration(
212223
this.GetPropertyTypeForBuilder(field),
@@ -239,6 +250,51 @@ protected NameSyntax GetFieldTypeForBuilder(MetaField field)
239250
: typeBasis;
240251
}
241252

253+
protected EventFieldDeclarationSyntax CreatePropertyChangedEvent()
254+
{
255+
var handler = SyntaxFactory.ParseTypeName("System.ComponentModel.PropertyChangedEventHandler");
256+
return SyntaxFactory.EventFieldDeclaration(
257+
SyntaxFactory.VariableDeclaration(handler)
258+
.AddVariables(SyntaxFactory.VariableDeclarator(nameof(System.ComponentModel.INotifyPropertyChanged.PropertyChanged))))
259+
.WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword)));
260+
}
261+
262+
protected MethodDeclarationSyntax CreateOnPropertyChangedMethod()
263+
{
264+
var callerMemberName = SyntaxFactory.ParseName("System.Runtime.CompilerServices.CallerMemberNameAttribute");
265+
var propertyNameParameterName = SyntaxFactory.IdentifierName("propertyName");
266+
var evt = SyntaxFactory.MemberAccessExpression(
267+
SyntaxKind.SimpleMemberAccessExpression,
268+
SyntaxFactory.ThisExpression(),
269+
SyntaxFactory.IdentifierName(nameof(System.ComponentModel.INotifyPropertyChanged.PropertyChanged)));
270+
var invokeMethod = SyntaxFactory.ConditionalAccessExpression(
271+
evt,
272+
SyntaxFactory.InvocationExpression(
273+
SyntaxFactory.MemberBindingExpression(SyntaxFactory.IdentifierName(nameof(System.ComponentModel.PropertyChangedEventHandler.Invoke))),
274+
SyntaxFactory.ArgumentList().AddArguments(
275+
SyntaxFactory.Argument(SyntaxFactory.ThisExpression()),
276+
SyntaxFactory.Argument(
277+
SyntaxFactory.ObjectCreationExpression(
278+
SyntaxFactory.ParseTypeName("System.ComponentModel.PropertyChangedEventArgs"),
279+
SyntaxFactory.ArgumentList().AddArguments(
280+
SyntaxFactory.Argument(propertyNameParameterName)),
281+
null)))));
282+
var body = SyntaxFactory.Block(
283+
SyntaxFactory.ExpressionStatement(invokeMethod));
284+
return SyntaxFactory.MethodDeclaration(
285+
SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.VoidKeyword)),
286+
OnPropertyChangedMethodName.Identifier)
287+
.AddParameterListParameters(
288+
SyntaxFactory.Parameter(propertyNameParameterName.Identifier)
289+
.WithType(SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.StringKeyword)))
290+
.AddAttributeLists(SyntaxFactory.AttributeList().AddAttributes(SyntaxFactory.Attribute(callerMemberName)))
291+
.WithDefault(SyntaxFactory.EqualsValueClause(SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal(string.Empty)))))
292+
.AddModifiers(
293+
SyntaxFactory.Token(SyntaxKind.ProtectedKeyword),
294+
SyntaxFactory.Token(SyntaxKind.VirtualKeyword))
295+
.WithBody(body);
296+
}
297+
242298
protected MethodDeclarationSyntax CreateToImmutableMethod()
243299
{
244300
// var fieldName = this.fieldName.IsDefined ? this.fieldName.Value?.ToImmutable() : this.immutable.FieldName;

0 commit comments

Comments
 (0)