diff --git a/README.md b/README.md index 6d5a239..191920a 100644 --- a/README.md +++ b/README.md @@ -25,9 +25,10 @@ This documentation covers using ReactiveUI Source Generators to simplify and enh ReactiveUI Source Generators automatically generate ReactiveUI objects to streamline your code. These Source Generators are designed to work with ReactiveUI V19.5.31+ and support the following features: - `[Reactive]` With field and access modifiers, partial property support (C# 13 Visual Studio Version 17.12.0), partial properties with initializer support (C# preview only) -- `[Reactive(SetModifier = AccessModifier.Protected)]` With field and access modifiers, (Not Required for partial properties, configure set accessor with the property decalaration). +- `[Reactive(SetModifier = AccessModifier.Protected)]` With field and access modifiers, (Not Required for partial properties, configure set accessor with the property declaration). - `[Reactive(Inheritance = InheritanceModifier.Virtual)]` With field and access modifiers. This will generate a virtual property. -- `[Reactive(UseRequired = true)]` With field and access modifiers. This will generate a required property, (Not Required for partial properties, use required keyword for property decalaration). +- `[Reactive(UseRequired = true)]` With field and access modifiers. This will generate a required property, (Not Required for partial properties, use required keyword for property declaration). +- `[Reactive(nameof(RaiseProperty1), nameof(RaiseProperty2))]` With field and property changed notification for additional properties. - `[ObservableAsProperty]` With field, method, Observable property and partial property support (C# 13 Visual Studio Version 17.12.0) - `[ObservableAsProperty(ReadOnly = false)]` Removes readonly keyword from the generated helper field - `[ObservableAsProperty(PropertyName = "ReadOnlyPropertyName")]` @@ -91,6 +92,9 @@ Generates a derived list from a `ReadOnlyObservableCollection` backing field. ### `[ReactiveCollection]` Generates property changed notifications on add, remove, and new actions on an `ObservableCollection` backing field. +### `[IReactiveObject]` +Generates `IReactiveObject` implementation for classes not able to inherit from `ReactiveObject`. + ## Historical Approach ### Read-Write Properties @@ -685,7 +689,7 @@ public partial class MyReactiveClass : ReactiveObject } ``` -### ReactiveObject implementation for classes not able to inherit from ReactiveObject +### IReactiveObject implementation for classes not able to inherit from ReactiveObject ```csharp using ReactiveUI; using ReactiveUI.SourceGenerators; diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactiveFromPartialWithAlsoNotify#ReactiveUI.SourceGenerators.AccessModifier.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactiveFromPartialWithAlsoNotify#ReactiveUI.SourceGenerators.AccessModifier.g.verified.cs new file mode 100644 index 0000000..b46677d --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactiveFromPartialWithAlsoNotify#ReactiveUI.SourceGenerators.AccessModifier.g.verified.cs @@ -0,0 +1,58 @@ +//HintName: ReactiveUI.SourceGenerators.AccessModifier.g.cs +// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +// +#pragma warning disable +#nullable enable +namespace ReactiveUI.SourceGenerators; + +/// +/// AccessModifier. +/// +internal enum AccessModifier +{ + Public, + Protected, + Internal, + Private, + InternalProtected, + PrivateProtected, + Init, +} + +/// +/// Property Access Modifier. +/// +internal enum PropertyAccessModifier +{ + Public, + Protected, + Internal, + Private, + InternalProtected, + PrivateProtected, +} + +/// +/// InheritanceModifier. +/// +internal enum InheritanceModifier +{ + None, + Virtual, + Override, + New, +} + +internal enum SplatRegistrationType +{ + None, + LazySingleton, + Constant, + PerRequest, +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactiveFromPartialWithAlsoNotify#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactiveFromPartialWithAlsoNotify#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs new file mode 100644 index 0000000..0e92495 --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactiveFromPartialWithAlsoNotify#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs @@ -0,0 +1,51 @@ +//HintName: ReactiveUI.SourceGenerators.ReactiveAttribute.g.cs +// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +// +#pragma warning disable +#nullable enable +namespace ReactiveUI.SourceGenerators; + +/// +/// ReactiveAttribute. +/// +/// +[global::System.AttributeUsage(global::System.AttributeTargets.Field | global::System.AttributeTargets.Property, AllowMultiple = false, Inherited = false)] +internal sealed class ReactiveAttribute : global::System.Attribute +{ + /// + /// Initializes a new instance of the class. + /// + public ReactiveAttribute(params string[] alsoNotify) + { + AlsoNotify = alsoNotify; + } + + /// + /// Gets the AccessModifier of the set property. + /// + /// + /// The AccessModifier of the set property. + /// + public AccessModifier SetModifier { get; init; } + + /// + /// Gets the InheritanceModifier of the property. + /// + public InheritanceModifier Inheritance { get; init; } + + /// + /// Use Required attribute to indicate that the property is required. + /// + public bool UseRequired { get; init; } + + /// + /// Gets the AlsoNotify properties to raise change notifications for. + /// + public string[]? AlsoNotify { get; } +} +#nullable restore +#pragma warning restore diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactiveFromPartialWithAlsoNotify#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactiveFromPartialWithAlsoNotify#TestNs.TestVM.Properties.g.verified.cs new file mode 100644 index 0000000..36376f8 --- /dev/null +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactiveFromPartialWithAlsoNotify#TestNs.TestVM.Properties.g.verified.cs @@ -0,0 +1,28 @@ +//HintName: TestNs.TestVM.Properties.g.cs +// +using ReactiveUI; + +#pragma warning disable +#nullable enable + +namespace TestNs +{ + + public partial class TestVM + { + + /// + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public int Test4 + { + get => _test4; + [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_test4")] + set + { + this.RaiseAndSetIfChanged(ref _test4, value); + } + } + } +} +#nullable restore +#pragma warning restore \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePartialProperties#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePartialProperties#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs index d4c80bd..0e92495 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePartialProperties#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePartialProperties#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs @@ -16,6 +16,14 @@ namespace ReactiveUI.SourceGenerators; [global::System.AttributeUsage(global::System.AttributeTargets.Field | global::System.AttributeTargets.Property, AllowMultiple = false, Inherited = false)] internal sealed class ReactiveAttribute : global::System.Attribute { + /// + /// Initializes a new instance of the class. + /// + public ReactiveAttribute(params string[] alsoNotify) + { + AlsoNotify = alsoNotify; + } + /// /// Gets the AccessModifier of the set property. /// @@ -26,13 +34,18 @@ internal sealed class ReactiveAttribute : global::System.Attribute /// /// Gets the InheritanceModifier of the property. - /// + /// public InheritanceModifier Inheritance { get; init; } /// /// Use Required attribute to indicate that the property is required. /// public bool UseRequired { get; init; } + + /// + /// Gets the AlsoNotify properties to raise change notifications for. + /// + public string[]? AlsoNotify { get; } } #nullable restore -#pragma warning restore \ No newline at end of file +#pragma warning restore diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactiveProperiesWithAttributes#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactiveProperiesWithAttributes#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs index d4c80bd..0e92495 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactiveProperiesWithAttributes#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactiveProperiesWithAttributes#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs @@ -16,6 +16,14 @@ namespace ReactiveUI.SourceGenerators; [global::System.AttributeUsage(global::System.AttributeTargets.Field | global::System.AttributeTargets.Property, AllowMultiple = false, Inherited = false)] internal sealed class ReactiveAttribute : global::System.Attribute { + /// + /// Initializes a new instance of the class. + /// + public ReactiveAttribute(params string[] alsoNotify) + { + AlsoNotify = alsoNotify; + } + /// /// Gets the AccessModifier of the set property. /// @@ -26,13 +34,18 @@ internal sealed class ReactiveAttribute : global::System.Attribute /// /// Gets the InheritanceModifier of the property. - /// + /// public InheritanceModifier Inheritance { get; init; } /// /// Use Required attribute to indicate that the property is required. /// public bool UseRequired { get; init; } + + /// + /// Gets the AlsoNotify properties to raise change notifications for. + /// + public string[]? AlsoNotify { get; } } #nullable restore -#pragma warning restore \ No newline at end of file +#pragma warning restore diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactiveProperiesWithAttributes#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactiveProperiesWithAttributes#TestNs.TestVM.Properties.g.verified.cs index cd0ffd2..8a2e02d 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactiveProperiesWithAttributes#TestNs.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactiveProperiesWithAttributes#TestNs.TestVM.Properties.g.verified.cs @@ -19,7 +19,10 @@ public int Test3 { get => _test3; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_test3")] - set => this.RaiseAndSetIfChanged(ref _test3, value); + set + { + this.RaiseAndSetIfChanged(ref _test3, value); + } } } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactiveProperties#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactiveProperties#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs index d4c80bd..0e92495 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactiveProperties#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactiveProperties#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs @@ -16,6 +16,14 @@ namespace ReactiveUI.SourceGenerators; [global::System.AttributeUsage(global::System.AttributeTargets.Field | global::System.AttributeTargets.Property, AllowMultiple = false, Inherited = false)] internal sealed class ReactiveAttribute : global::System.Attribute { + /// + /// Initializes a new instance of the class. + /// + public ReactiveAttribute(params string[] alsoNotify) + { + AlsoNotify = alsoNotify; + } + /// /// Gets the AccessModifier of the set property. /// @@ -26,13 +34,18 @@ internal sealed class ReactiveAttribute : global::System.Attribute /// /// Gets the InheritanceModifier of the property. - /// + /// public InheritanceModifier Inheritance { get; init; } /// /// Use Required attribute to indicate that the property is required. /// public bool UseRequired { get; init; } + + /// + /// Gets the AlsoNotify properties to raise change notifications for. + /// + public string[]? AlsoNotify { get; } } #nullable restore -#pragma warning restore \ No newline at end of file +#pragma warning restore diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactiveProperties#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactiveProperties#TestNs.TestVM.Properties.g.verified.cs index 49b034f..55a7f05 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactiveProperties#TestNs.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactiveProperties#TestNs.TestVM.Properties.g.verified.cs @@ -17,7 +17,10 @@ public int Test1 { get => _test1; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_test1")] - set => this.RaiseAndSetIfChanged(ref _test1, value); + set + { + this.RaiseAndSetIfChanged(ref _test1, value); + } } } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesCalledValue#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesCalledValue#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs index d4c80bd..0e92495 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesCalledValue#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesCalledValue#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs @@ -16,6 +16,14 @@ namespace ReactiveUI.SourceGenerators; [global::System.AttributeUsage(global::System.AttributeTargets.Field | global::System.AttributeTargets.Property, AllowMultiple = false, Inherited = false)] internal sealed class ReactiveAttribute : global::System.Attribute { + /// + /// Initializes a new instance of the class. + /// + public ReactiveAttribute(params string[] alsoNotify) + { + AlsoNotify = alsoNotify; + } + /// /// Gets the AccessModifier of the set property. /// @@ -26,13 +34,18 @@ internal sealed class ReactiveAttribute : global::System.Attribute /// /// Gets the InheritanceModifier of the property. - /// + /// public InheritanceModifier Inheritance { get; init; } /// /// Use Required attribute to indicate that the property is required. /// public bool UseRequired { get; init; } + + /// + /// Gets the AlsoNotify properties to raise change notifications for. + /// + public string[]? AlsoNotify { get; } } #nullable restore -#pragma warning restore \ No newline at end of file +#pragma warning restore diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesCalledValue#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesCalledValue#TestNs.TestVM.Properties.g.verified.cs index 283ab8d..f0515a5 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesCalledValue#TestNs.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesCalledValue#TestNs.TestVM.Properties.g.verified.cs @@ -17,7 +17,10 @@ public string Value { get => value; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("this.value")] - set => this.RaiseAndSetIfChanged(ref this.value, value); + set + { + this.RaiseAndSetIfChanged(ref this.value, value); + } } } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithAccess#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithAccess#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs index d4c80bd..0e92495 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithAccess#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithAccess#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs @@ -16,6 +16,14 @@ namespace ReactiveUI.SourceGenerators; [global::System.AttributeUsage(global::System.AttributeTargets.Field | global::System.AttributeTargets.Property, AllowMultiple = false, Inherited = false)] internal sealed class ReactiveAttribute : global::System.Attribute { + /// + /// Initializes a new instance of the class. + /// + public ReactiveAttribute(params string[] alsoNotify) + { + AlsoNotify = alsoNotify; + } + /// /// Gets the AccessModifier of the set property. /// @@ -26,13 +34,18 @@ internal sealed class ReactiveAttribute : global::System.Attribute /// /// Gets the InheritanceModifier of the property. - /// + /// public InheritanceModifier Inheritance { get; init; } /// /// Use Required attribute to indicate that the property is required. /// public bool UseRequired { get; init; } + + /// + /// Gets the AlsoNotify properties to raise change notifications for. + /// + public string[]? AlsoNotify { get; } } #nullable restore -#pragma warning restore \ No newline at end of file +#pragma warning restore diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithAccess#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithAccess#TestNs.TestVM.Properties.g.verified.cs index 89940cb..03151e4 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithAccess#TestNs.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithAccess#TestNs.TestVM.Properties.g.verified.cs @@ -17,7 +17,10 @@ public int Test2 { get => _test2; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_test2")] - set => this.RaiseAndSetIfChanged(ref _test2, value); + set + { + this.RaiseAndSetIfChanged(ref _test2, value); + } } } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithAttributesAccessAndInheritance#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithAttributesAccessAndInheritance#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs index d4c80bd..0e92495 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithAttributesAccessAndInheritance#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithAttributesAccessAndInheritance#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs @@ -16,6 +16,14 @@ namespace ReactiveUI.SourceGenerators; [global::System.AttributeUsage(global::System.AttributeTargets.Field | global::System.AttributeTargets.Property, AllowMultiple = false, Inherited = false)] internal sealed class ReactiveAttribute : global::System.Attribute { + /// + /// Initializes a new instance of the class. + /// + public ReactiveAttribute(params string[] alsoNotify) + { + AlsoNotify = alsoNotify; + } + /// /// Gets the AccessModifier of the set property. /// @@ -26,13 +34,18 @@ internal sealed class ReactiveAttribute : global::System.Attribute /// /// Gets the InheritanceModifier of the property. - /// + /// public InheritanceModifier Inheritance { get; init; } /// /// Use Required attribute to indicate that the property is required. /// public bool UseRequired { get; init; } + + /// + /// Gets the AlsoNotify properties to raise change notifications for. + /// + public string[]? AlsoNotify { get; } } #nullable restore -#pragma warning restore \ No newline at end of file +#pragma warning restore diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithAttributesAccessAndInheritance#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithAttributesAccessAndInheritance#TestNs.TestVM.Properties.g.verified.cs index 92267be..6eb33cf 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithAttributesAccessAndInheritance#TestNs.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithAttributesAccessAndInheritance#TestNs.TestVM.Properties.g.verified.cs @@ -19,7 +19,10 @@ public string? Name { get => _name; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_name")] - set => this.RaiseAndSetIfChanged(ref _name, value); + set + { + this.RaiseAndSetIfChanged(ref _name, value); + } } } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithIdenticalClass#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithIdenticalClass#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs index d4c80bd..0e92495 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithIdenticalClass#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithIdenticalClass#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs @@ -16,6 +16,14 @@ namespace ReactiveUI.SourceGenerators; [global::System.AttributeUsage(global::System.AttributeTargets.Field | global::System.AttributeTargets.Property, AllowMultiple = false, Inherited = false)] internal sealed class ReactiveAttribute : global::System.Attribute { + /// + /// Initializes a new instance of the class. + /// + public ReactiveAttribute(params string[] alsoNotify) + { + AlsoNotify = alsoNotify; + } + /// /// Gets the AccessModifier of the set property. /// @@ -26,13 +34,18 @@ internal sealed class ReactiveAttribute : global::System.Attribute /// /// Gets the InheritanceModifier of the property. - /// + /// public InheritanceModifier Inheritance { get; init; } /// /// Use Required attribute to indicate that the property is required. /// public bool UseRequired { get; init; } + + /// + /// Gets the AlsoNotify properties to raise change notifications for. + /// + public string[]? AlsoNotify { get; } } #nullable restore -#pragma warning restore \ No newline at end of file +#pragma warning restore diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithIdenticalClass#TestNs1.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithIdenticalClass#TestNs1.TestVM.Properties.g.verified.cs index 0e7ba6b..bb716ed 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithIdenticalClass#TestNs1.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithIdenticalClass#TestNs1.TestVM.Properties.g.verified.cs @@ -19,7 +19,10 @@ public string? Name { get => _name; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_name")] - set => this.RaiseAndSetIfChanged(ref _name, value); + set + { + this.RaiseAndSetIfChanged(ref _name, value); + } } } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithIdenticalClass#TestNs2.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithIdenticalClass#TestNs2.TestVM.Properties.g.verified.cs index f27308e..75dc500 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithIdenticalClass#TestNs2.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithIdenticalClass#TestNs2.TestVM.Properties.g.verified.cs @@ -19,7 +19,10 @@ public string? Name { get => _name; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_name")] - set => this.RaiseAndSetIfChanged(ref _name, value); + set + { + this.RaiseAndSetIfChanged(ref _name, value); + } } } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithInit#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithInit#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs index d4c80bd..0e92495 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithInit#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithInit#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs @@ -16,6 +16,14 @@ namespace ReactiveUI.SourceGenerators; [global::System.AttributeUsage(global::System.AttributeTargets.Field | global::System.AttributeTargets.Property, AllowMultiple = false, Inherited = false)] internal sealed class ReactiveAttribute : global::System.Attribute { + /// + /// Initializes a new instance of the class. + /// + public ReactiveAttribute(params string[] alsoNotify) + { + AlsoNotify = alsoNotify; + } + /// /// Gets the AccessModifier of the set property. /// @@ -26,13 +34,18 @@ internal sealed class ReactiveAttribute : global::System.Attribute /// /// Gets the InheritanceModifier of the property. - /// + /// public InheritanceModifier Inheritance { get; init; } /// /// Use Required attribute to indicate that the property is required. /// public bool UseRequired { get; init; } + + /// + /// Gets the AlsoNotify properties to raise change notifications for. + /// + public string[]? AlsoNotify { get; } } #nullable restore -#pragma warning restore \ No newline at end of file +#pragma warning restore diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithInit#TestNs.TestVM.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithInit#TestNs.TestVM.Properties.g.verified.cs index f1b9a0e..1514954 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithInit#TestNs.TestVM.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithInit#TestNs.TestVM.Properties.g.verified.cs @@ -17,7 +17,10 @@ public string MustBeSet { get => _mustBeSet; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_mustBeSet")] - set => this.RaiseAndSetIfChanged(ref _mustBeSet, value); + set + { + this.RaiseAndSetIfChanged(ref _mustBeSet, value); + } } } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithNestedClass#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithNestedClass#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs index d4c80bd..0e92495 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithNestedClass#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithNestedClass#ReactiveUI.SourceGenerators.ReactiveAttribute.g.verified.cs @@ -16,6 +16,14 @@ namespace ReactiveUI.SourceGenerators; [global::System.AttributeUsage(global::System.AttributeTargets.Field | global::System.AttributeTargets.Property, AllowMultiple = false, Inherited = false)] internal sealed class ReactiveAttribute : global::System.Attribute { + /// + /// Initializes a new instance of the class. + /// + public ReactiveAttribute(params string[] alsoNotify) + { + AlsoNotify = alsoNotify; + } + /// /// Gets the AccessModifier of the set property. /// @@ -26,13 +34,18 @@ internal sealed class ReactiveAttribute : global::System.Attribute /// /// Gets the InheritanceModifier of the property. - /// + /// public InheritanceModifier Inheritance { get; init; } /// /// Use Required attribute to indicate that the property is required. /// public bool UseRequired { get; init; } + + /// + /// Gets the AlsoNotify properties to raise change notifications for. + /// + public string[]? AlsoNotify { get; } } #nullable restore -#pragma warning restore \ No newline at end of file +#pragma warning restore diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithNestedClass#TestNs1.TestViewModel3+TestInnerClass1.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithNestedClass#TestNs1.TestViewModel3+TestInnerClass1.Properties.g.verified.cs index f716a5c..68d382c 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithNestedClass#TestNs1.TestViewModel3+TestInnerClass1.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithNestedClass#TestNs1.TestViewModel3+TestInnerClass1.Properties.g.verified.cs @@ -19,7 +19,10 @@ public int TestInner1 { get => _testInner1; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_testInner1")] - set => this.RaiseAndSetIfChanged(ref _testInner1, value); + set + { + this.RaiseAndSetIfChanged(ref _testInner1, value); + } } /// @@ -28,7 +31,10 @@ public int TestInner11 { get => _testInner11; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_testInner11")] - set => this.RaiseAndSetIfChanged(ref _testInner11, value); + set + { + this.RaiseAndSetIfChanged(ref _testInner11, value); + } } } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithNestedClass#TestNs1.TestViewModel3+TestInnerClass2+TestInnerClass3.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithNestedClass#TestNs1.TestViewModel3+TestInnerClass2+TestInnerClass3.Properties.g.verified.cs index 21bede2..64e8205 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithNestedClass#TestNs1.TestViewModel3+TestInnerClass2+TestInnerClass3.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithNestedClass#TestNs1.TestViewModel3+TestInnerClass2+TestInnerClass3.Properties.g.verified.cs @@ -21,7 +21,10 @@ public int TestInner3 { get => _testInner3; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_testInner3")] - set => this.RaiseAndSetIfChanged(ref _testInner3, value); + set + { + this.RaiseAndSetIfChanged(ref _testInner3, value); + } } /// @@ -30,7 +33,10 @@ public int TestInner33 { get => _testInner33; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_testInner33")] - set => this.RaiseAndSetIfChanged(ref _testInner33, value); + set + { + this.RaiseAndSetIfChanged(ref _testInner33, value); + } } } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithNestedClass#TestNs1.TestViewModel3+TestInnerClass2.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithNestedClass#TestNs1.TestViewModel3+TestInnerClass2.Properties.g.verified.cs index ba38f3a..82b2dcb 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithNestedClass#TestNs1.TestViewModel3+TestInnerClass2.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithNestedClass#TestNs1.TestViewModel3+TestInnerClass2.Properties.g.verified.cs @@ -19,7 +19,10 @@ public int TestInner2 { get => _testInner2; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_testInner2")] - set => this.RaiseAndSetIfChanged(ref _testInner2, value); + set + { + this.RaiseAndSetIfChanged(ref _testInner2, value); + } } /// @@ -28,7 +31,10 @@ public int TestInner22 { get => _testInner22; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_testInner22")] - set => this.RaiseAndSetIfChanged(ref _testInner22, value); + set + { + this.RaiseAndSetIfChanged(ref _testInner22, value); + } } } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithNestedClass#TestNs1.TestViewModel3.Properties.g.verified.cs b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithNestedClass#TestNs1.TestViewModel3.Properties.g.verified.cs index 898c290..b8e54c8 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithNestedClass#TestNs1.TestViewModel3.Properties.g.verified.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithNestedClass#TestNs1.TestViewModel3.Properties.g.verified.cs @@ -17,7 +17,10 @@ public float TestVM3Property { get => _testVM3Property; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_testVM3Property")] - set => this.RaiseAndSetIfChanged(ref _testVM3Property, value); + set + { + this.RaiseAndSetIfChanged(ref _testVM3Property, value); + } } /// @@ -26,7 +29,10 @@ public float TestVM3Property2 { get => _testVM3Property2; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_testVM3Property2")] - set => this.RaiseAndSetIfChanged(ref _testVM3Property2, value); + set + { + this.RaiseAndSetIfChanged(ref _testVM3Property2, value); + } } } } diff --git a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ReactiveGeneratorTests.cs b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ReactiveGeneratorTests.cs index 832455a..f3ffa0b 100644 --- a/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ReactiveGeneratorTests.cs +++ b/src/ReactiveUI.SourceGenerator.Tests/UnitTests/ReactiveGeneratorTests.cs @@ -325,4 +325,32 @@ public partial class TestVM : ReactiveObject // Act: Initialize the helper and run the generator. Assert: Verify the generated code. return TestHelper.TestPass(sourceCode); } + + /// + /// Tests reactive property generation from a partial class with AlsoNotify support. + /// + /// A task to monitor the async. + [Test] + public Task FromReactiveFromPartialWithAlsoNotify() + { + // Arrange: Setup the source code that matches the generator input expectations. + const string sourceCode = """ + using System; + using ReactiveUI; + using ReactiveUI.SourceGenerators; + using System.Reactive.Linq; + namespace TestNs; + public partial class TestVM : ReactiveObject + { + [Reactive(nameof(OtherNotifyProperty))] + private int _test4; + + // This property is notified when Test4 changes + public int OtherNotifyProperty { get; set; } + } + """; + + // Act: Initialize the helper and run the generator. Assert: Verify the generated code. + return TestHelper.TestPass(sourceCode); + } } diff --git a/src/ReactiveUI.SourceGenerators.Execute/TestViewModel.cs b/src/ReactiveUI.SourceGenerators.Execute/TestViewModel.cs index e0f51a7..7e3a739 100644 --- a/src/ReactiveUI.SourceGenerators.Execute/TestViewModel.cs +++ b/src/ReactiveUI.SourceGenerators.Execute/TestViewModel.cs @@ -70,7 +70,7 @@ public partial class TestViewModel : ReactiveObject, IActivatableViewModel, IDis [Reactive(Inheritance = InheritanceModifier.Virtual, SetModifier = AccessModifier.Protected)] private string? _name; - [Reactive(SetModifier = AccessModifier.Init, UseRequired = true)] + [Reactive(nameof(MyDoubleProperty), nameof(MyStringProperty), SetModifier = AccessModifier.Init, UseRequired = true)] private string _mustBeSet; [Reactive] diff --git a/src/ReactiveUI.SourceGenerators.Roslyn/AttributeDefinitions.cs b/src/ReactiveUI.SourceGenerators.Roslyn/AttributeDefinitions.cs index 2cdfdd8..55e3dbf 100644 --- a/src/ReactiveUI.SourceGenerators.Roslyn/AttributeDefinitions.cs +++ b/src/ReactiveUI.SourceGenerators.Roslyn/AttributeDefinitions.cs @@ -184,6 +184,14 @@ namespace ReactiveUI.SourceGenerators; [global::System.AttributeUsage(global::System.AttributeTargets.Field | global::System.AttributeTargets.Property, AllowMultiple = false, Inherited = false)] internal sealed class ReactiveAttribute : global::System.Attribute { + /// + /// Initializes a new instance of the class. + /// + public ReactiveAttribute(params string[] alsoNotify) + { + AlsoNotify = alsoNotify; + } + /// /// Gets the AccessModifier of the set property. /// @@ -194,13 +202,18 @@ internal sealed class ReactiveAttribute : global::System.Attribute /// /// Gets the InheritanceModifier of the property. - /// + /// public InheritanceModifier Inheritance { get; init; } /// /// Use Required attribute to indicate that the property is required. /// public bool UseRequired { get; init; } + + /// + /// Gets the AlsoNotify properties to raise change notifications for. + /// + public string[]? AlsoNotify { get; } } #nullable restore #pragma warning restore @@ -225,6 +238,14 @@ namespace ReactiveUI.SourceGenerators; [global::System.AttributeUsage(global::System.AttributeTargets.Field, AllowMultiple = false, Inherited = false)] internal sealed class ReactiveAttribute : global::System.Attribute { + /// + /// Initializes a new instance of the class. + /// + public ReactiveAttribute(params string[] alsoNotify) + { + AlsoNotify = alsoNotify; + } + /// /// Gets the AccessModifier of the set property. /// @@ -235,13 +256,18 @@ internal sealed class ReactiveAttribute : global::System.Attribute /// /// Gets the InheritanceModifier of the property. - /// + /// public InheritanceModifier Inheritance { get; init; } /// /// Use Required attribute to indicate that the property is required. /// public bool UseRequired { get; init; } + + /// + /// Gets the AlsoNotify properties to raise change notifications for. + /// + public string[]? AlsoNotify { get; } } #nullable restore #pragma warning restore diff --git a/src/ReactiveUI.SourceGenerators.Roslyn/Reactive/Models/PropertyInfo.cs b/src/ReactiveUI.SourceGenerators.Roslyn/Reactive/Models/PropertyInfo.cs index 0488b5b..963ae10 100644 --- a/src/ReactiveUI.SourceGenerators.Roslyn/Reactive/Models/PropertyInfo.cs +++ b/src/ReactiveUI.SourceGenerators.Roslyn/Reactive/Models/PropertyInfo.cs @@ -23,4 +23,5 @@ internal sealed record PropertyInfo( string Inheritance, string UseRequired, bool IsProperty, - string PropertyAccessModifier); + string PropertyAccessModifier, + EquatableArray AlsoNotify); diff --git a/src/ReactiveUI.SourceGenerators.Roslyn/Reactive/ReactiveGenerator.Execute.cs b/src/ReactiveUI.SourceGenerators.Roslyn/Reactive/ReactiveGenerator.Execute.cs index 9424d57..568399e 100644 --- a/src/ReactiveUI.SourceGenerators.Roslyn/Reactive/ReactiveGenerator.Execute.cs +++ b/src/ReactiveUI.SourceGenerators.Roslyn/Reactive/ReactiveGenerator.Execute.cs @@ -149,6 +149,19 @@ public sealed partial class ReactiveGenerator token.ThrowIfCancellationRequested(); + var alsoNotify = attributeData.GetConstructorArguments() + .Where(notify => !string.IsNullOrEmpty(notify) && !string.Equals(notify, propertyName, StringComparison.Ordinal)); + using var alsoNotifyBuilder = ImmutableArrayBuilder.Rent(); + if (alsoNotify is not null) + { + foreach (var notify in alsoNotify) + { + alsoNotifyBuilder.Add(notify!); + } + } + + token.ThrowIfCancellationRequested(); + // Get the containing type info var targetInfo = TargetInfo.From(propertySymbol.ContainingType); @@ -167,7 +180,8 @@ public sealed partial class ReactiveGenerator inheritance, useRequired, true, - propertyAccessModifier!), + propertyAccessModifier!, + alsoNotifyBuilder.ToImmutable()), builder.ToImmutable()); } #endif @@ -275,6 +289,19 @@ public sealed partial class ReactiveGenerator token.ThrowIfCancellationRequested(); + var alsoNotify = attributeData.GetConstructorArguments() + .Where(notify => !string.IsNullOrEmpty(notify) && !string.Equals(notify, propertyName, StringComparison.Ordinal)); + using var alsoNotifyBuilder = ImmutableArrayBuilder.Rent(); + if (alsoNotify is not null) + { + foreach (var notify in alsoNotify) + { + alsoNotifyBuilder.Add(notify!); + } + } + + token.ThrowIfCancellationRequested(); + // Get the containing type info var targetInfo = TargetInfo.From(fieldSymbol.ContainingType); @@ -293,7 +320,8 @@ public sealed partial class ReactiveGenerator inheritance, useRequired, false, - "public"), + "public", + alsoNotifyBuilder.ToImmutable()), builder.ToImmutable()); } @@ -396,6 +424,12 @@ private static string GetPropertySyntax(PropertyInfo propertyInfo) propertyAttributes = string.Join("\n ", AttributeDefinitions.ExcludeFromCodeCoverage.Concat(propertyInfo.ForwardedAttributes)); } + var alsoNotifyAttributes = string.Empty; + if (!propertyInfo.AlsoNotify.IsEmpty) + { + alsoNotifyAttributes = string.Concat(propertyInfo.AlsoNotify.Select(an => $"\n this.RaisePropertyChanged(nameof({an}));")); + } + var accessModifier = propertyInfo.PropertyAccessModifier; var setAccessModifier = propertyInfo.SetAccessModifier; @@ -411,7 +445,10 @@ private static string GetPropertySyntax(PropertyInfo propertyInfo) { get => {{getFieldName}}; [global::System.Diagnostics.CodeAnalysis.MemberNotNull("{{setFieldName}}")] - {{setAccessModifier}} => this.RaiseAndSetIfChanged(ref {{setFieldName}}, value); + {{setAccessModifier}} + { + this.RaiseAndSetIfChanged(ref {{setFieldName}}, value);{{alsoNotifyAttributes}} + } } """; } @@ -422,7 +459,14 @@ private static string GetPropertySyntax(PropertyInfo propertyInfo) /// [global::System.CodeDom.Compiler.GeneratedCode("{{GeneratorName}}", "{{GeneratorVersion}}")] {{propertyAttributes}} - {{accessModifier}}{{propertyInfo.Inheritance}} {{propertyInfo.UseRequired}}{{partialModifier}}{{propertyInfo.TypeNameWithNullabilityAnnotations}} {{propertyInfo.PropertyName}} { get => {{getFieldName}}; {{setAccessModifier}} => this.RaiseAndSetIfChanged(ref {{setFieldName}}, value); } + {{accessModifier}}{{propertyInfo.Inheritance}} {{propertyInfo.UseRequired}}{{partialModifier}}{{propertyInfo.TypeNameWithNullabilityAnnotations}} {{propertyInfo.PropertyName}} + { + get => {{getFieldName}}; + {{setAccessModifier}} + { + this.RaiseAndSetIfChanged(ref {{setFieldName}}, value);{{alsoNotifyAttributes}} + } + } """; } }