Skip to content

Commit 4920f43

Browse files
committed
bind on fields, not properties
1 parent 0a4547b commit 4920f43

File tree

4 files changed

+52
-44
lines changed

4 files changed

+52
-44
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ A lightweight WPF ViewModel framework with automatic source generation that elim
1616
### Installation
1717

1818
```xml
19-
<PackageReference Include="SimpleViewModel" Version="0.9.0" />
19+
<PackageReference Include="SimpleViewModel" Version="0.9.3" />
2020
```
2121

2222
### Basic Usage

SimpleViewModel/BindAttribute.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
namespace SimpleViewModel;
22

3-
[AttributeUsage(AttributeTargets.Property)]
3+
[AttributeUsage(AttributeTargets.Field)]
44
public sealed class BindAttribute : Attribute;

SimpleViewModel/SimpleViewModel.csproj

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
1111
<PackageId>SimpleViewModel</PackageId>
12-
<Version>0.9.2</Version>
12+
<Version>0.9.3</Version>
1313
<Authors>Derek Gooding</Authors>
1414
<Company>Derek Gooding</Company>
1515
<Description>
@@ -31,20 +31,20 @@
3131

3232
<PackageLicenseExpression>MIT</PackageLicenseExpression>
3333
<PackageReadmeFile>README.md</PackageReadmeFile>
34-
<PackageProjectUrl>https://github.com/DerekGooding/SimpleMVVM</PackageProjectUrl>
35-
<RepositoryUrl>https://github.com/DerekGooding/SimpleMVVM</RepositoryUrl>
36-
<PackageBugTrackerUrl>https://github.com/DerekGooding/SimpleMVVM/issues</PackageBugTrackerUrl>
34+
<PackageProjectUrl>https://github.com/DerekGooding/SimpleViewModel</PackageProjectUrl>
35+
<RepositoryUrl>https://github.com/DerekGooding/SimpleViewModel</RepositoryUrl>
36+
<PackageBugTrackerUrl>https://github.com/DerekGooding/SimpleViewModel/issues</PackageBugTrackerUrl>
3737
<RepositoryType>git</RepositoryType>
3838
<RepositoryBranch>main</RepositoryBranch>
3939
<RepositoryCommit>$(GitCommitId)</RepositoryCommit>
4040

4141
<PackageIcon>Icon.png</PackageIcon>
4242
<GenerateDocumentationFile>true</GenerateDocumentationFile>
43-
<DocumentationFile>bin\SimpleMVVM.xml</DocumentationFile>
43+
<DocumentationFile>bin\SimpleViewModel.xml</DocumentationFile>
4444

4545
<Copyright>Copyright © Derek Gooding 2025</Copyright>
46-
<Product>SimpleMVVM</Product>
47-
<AssemblyTitle>SimpleMVVM - Lightweight windows only WPF MVVM with Source Generation</AssemblyTitle>
46+
<Product>SimpleViewModel</Product>
47+
<AssemblyTitle>SimpleViewModel - Lightweight windows only WPF MVVM with Source Generation</AssemblyTitle>
4848
<AssemblyDescription>$(Description)</AssemblyDescription>
4949
<NeutralLanguage>en-US</NeutralLanguage>
5050

ViewModelGenerator/ViewModelGenerator.cs

Lines changed: 43 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -30,56 +30,64 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
3030

3131
context.RegisterSourceOutput(compilationAndClasses, static (spc, source) =>
3232
{
33-
var (compilation, classNodes) = source;
33+
var (compilation, classNodes) = source;
3434

35-
foreach (var classNode in classNodes)
36-
{
37-
var model = compilation.GetSemanticModel(classNode.SyntaxTree);
38-
if (model.GetDeclaredSymbol(classNode) is not INamedTypeSymbol symbol) continue;
35+
foreach (var classNode in classNodes)
36+
{
37+
var model = compilation.GetSemanticModel(classNode.SyntaxTree);
38+
if (model.GetDeclaredSymbol(classNode) is not INamedTypeSymbol symbol) continue;
3939

40-
if (!symbol.GetAttributes().Any(attr => attr.AttributeClass?.Name == "ViewModelAttribute")) continue;
40+
if (!symbol.GetAttributes().Any(attr => attr.AttributeClass?.Name == "ViewModelAttribute")) continue;
4141

42-
var className = symbol.Name;
43-
var generatedName = $"{className}";
44-
var namespaceName = symbol.ContainingNamespace.ToDisplayString();
42+
var className = symbol.Name;
43+
var generatedName = $"{className}";
44+
var namespaceName = symbol.ContainingNamespace.ToDisplayString();
4545

46-
var bindFields = symbol.GetMembers()
47-
.OfType<IFieldSymbol>()
48-
.Where(f => f.GetAttributes().Any(attr => attr.AttributeClass?.Name == "BindAttribute"))
49-
.ToList();
46+
var bindFields = symbol.GetMembers()
47+
.OfType<IFieldSymbol>()
48+
.Where(f => f.GetAttributes().Any(attr => attr.AttributeClass?.Name == "BindAttribute"))
49+
.ToList();
5050

51-
var commandMethods = symbol.GetMembers()
52-
.OfType<IMethodSymbol>()
53-
.Where(m => m.MethodKind == MethodKind.Ordinary &&
54-
m.GetAttributes().Any(attr => attr.AttributeClass?.Name == "CommandAttribute"))
55-
.ToList();
51+
var commandMethods = symbol.GetMembers()
52+
.OfType<IMethodSymbol>()
53+
.Where(m => m.MethodKind == MethodKind.Ordinary &&
54+
m.GetAttributes().Any(attr => attr.AttributeClass?.Name == "CommandAttribute"))
55+
.ToList();
5656

57-
// Generate ViewModel partial class
58-
var viewModelBuilder = new StringBuilder($@"
59-
using SimpleViewModel.BaseClasses;
57+
// Generate ViewModel partial class
58+
var viewModelBuilder = new StringBuilder(
59+
$@"using SimpleViewModel.BaseClasses;
6060
6161
namespace {namespaceName}
6262
{{
6363
public partial class {className} : BaseViewModel
64-
{{
65-
");
64+
{{");
6665

67-
foreach (var field in bindFields)
68-
{
69-
viewModelBuilder.AppendLine($" public {field.Type} {ToPascal(field.Name)} {{ get; set; }}");
70-
}
66+
foreach (var field in bindFields)
67+
{
68+
viewModelBuilder.AppendLine($" public {field.Type} {ToPascal(field.Name)} {{ get; set; }}");
69+
}
70+
71+
viewModelBuilder.AppendLine();
72+
73+
foreach (var field in bindFields)
74+
{
75+
var fieldType = field.Type.ToDisplayString();
76+
var fieldName = ToPascal(field.Name);
7177

72-
viewModelBuilder.AppendLine();
78+
viewModelBuilder.AppendLine($" public {fieldType} {fieldName} {{ get => {field.Name}; set => SetProperty(ref {field.Name}, value); }}");
79+
}
7380

74-
foreach (var method in commandMethods)
75-
{
76-
var commandClassName = $"Command_{method.Name}";
77-
var commandFieldName = $"{ToPascal(method.Name)}Command";
78-
viewModelBuilder.AppendLine($" public {commandClassName} {commandFieldName} {{ get; }} = new {commandClassName}(this);");
81+
foreach (var method in commandMethods)
82+
{
83+
var commandClassName = $"Command_{method.Name}";
84+
var commandFieldName = $"{ToPascal(method.Name)}Command";
85+
viewModelBuilder.AppendLine($" private {commandClassName} _{commandFieldName} {{ get; }} = new {commandClassName}(this);");
86+
viewModelBuilder.AppendLine($" public {commandClassName} {commandFieldName} => _{commandFieldName} ??= new(this);");
7987

8088
// Generate command class per method
81-
var commandBuilder = new StringBuilder($@"
82-
using SimpleViewModel.BaseClasses;
89+
var commandBuilder = new StringBuilder(
90+
$@"using SimpleViewModel.BaseClasses;
8391
8492
namespace {namespaceName}
8593
{{

0 commit comments

Comments
 (0)