Skip to content

Commit b491db7

Browse files
committed
push project
1 parent 9c28c4c commit b491db7

File tree

13 files changed

+185
-244
lines changed

13 files changed

+185
-244
lines changed

README.md

Lines changed: 175 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,179 +1,242 @@
1-
# SimpleInjection
1+
# SimpleMVVM
22

3-
A lightweight dependency injection library for C# that combines simple DI container functionality with powerful source generation for content management.
3+
A lightweight WPF MVVM framework with automatic source generation that eliminates boilerplate code while maintaining full control over your view models.
44

55
## Features
66

7-
### 🚀 Simple Dependency Injection
8-
- **Attribute-based registration** - Mark classes with `[Singleton]`, `[Scoped]`, or `[Transient]`
9-
- **Automatic service discovery** - No manual registration required
10-
- **Constructor injection** - Automatic dependency resolution
11-
- **Scope management** - Built-in scoped service lifetime management
12-
13-
### ⚡ Content Source Generation
14-
- **Automatic enum generation** - Creates enums from your content collections
15-
- **Type-safe access** - Generated helper methods for accessing content by enum or index
16-
- **Performance optimized** - Uses `NamedComparer<T>` for fast dictionary lookups
17-
- **Roslyn analyzers** - Enforces best practices and catches common mistakes
7+
- **Zero Boilerplate Commands**: Transform methods into ICommand properties with a simple `[Command]` attribute
8+
- **Automatic Property Binding**: Generate observable properties from fields using `[Bind]` attribute
9+
- **Source Generation**: All code generation happens at compile time with no runtime reflection
10+
- **Lightweight**: Minimal dependencies and overhead
11+
- **Type Safe**: Full IntelliSense support and compile-time validation
12+
- **WPF Optimized**: Built specifically for WPF applications with proper CommandManager integration
1813

1914
## Quick Start
2015

21-
### 1. Install the Package
22-
```bash
23-
dotnet add package SimpleInjection
16+
### Installation
17+
18+
```xml
19+
<PackageReference Include="SimpleMVVM" Version="0.9.0" />
2420
```
2521

26-
### 2. Dependency Injection Usage
22+
### Basic Usage
2723

28-
Mark your classes with lifetime attributes:
24+
1. **Create a ViewModel**:
2925

3026
```csharp
31-
[Singleton]
32-
public class DatabaseService
33-
{
34-
public void Connect() => Console.WriteLine("Connected to database");
35-
}
27+
using SimpleMVVM;
28+
using SimpleMVVM.BaseClasses;
3629

37-
[Scoped]
38-
public class UserService
30+
[ViewModel]
31+
public partial class MainViewModel : BaseViewModel
3932
{
40-
private readonly DatabaseService _database;
41-
42-
public UserService(DatabaseService database)
33+
[Command]
34+
public void SaveData()
4335
{
44-
_database = database;
36+
// Your save logic here
37+
MessageBox.Show("Data saved!");
38+
}
39+
40+
[Command]
41+
public void LoadData()
42+
{
43+
// Your load logic here
44+
MessageBox.Show("Data loaded!");
4545
}
46-
47-
public void GetUser() => _database.Connect();
4846
}
4947
```
5048

51-
Initialize and use the host:
49+
2. **Bind to XAML**:
50+
51+
```xml
52+
<Window x:Class="MyApp.MainWindow"
53+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
54+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
55+
<StackPanel>
56+
<Button Content="Save" Command="{Binding SaveDataCommand}" />
57+
<Button Content="Load" Command="{Binding LoadDataCommand}" />
58+
</StackPanel>
59+
</Window>
60+
```
61+
62+
3. **Set DataContext**:
5263

5364
```csharp
54-
var host = Host.Initialize();
65+
public partial class MainWindow : Window
66+
{
67+
public MainWindow()
68+
{
69+
InitializeComponent();
70+
DataContext = new MainViewModel();
71+
}
72+
}
73+
```
5574

56-
// Get singleton services directly
57-
var dbService = host.Get<DatabaseService>();
75+
That's it! The source generator automatically creates `SaveDataCommand` and `LoadDataCommand` properties for you.
5876

59-
// Create scopes for scoped services
60-
using var scope = host.CreateScope();
61-
var userService = scope.Get<UserService>();
62-
```
77+
## Advanced Features
6378

64-
### 3. Content Generation Usage
79+
### Observable Properties
6580

66-
Define your content classes:
81+
Use the `[Bind]` attribute to automatically generate observable properties:
6782

6883
```csharp
69-
// Your content item must implement INamed
70-
public record Material(string Name, string Color, int Durability) : INamed;
71-
72-
// Your content collection must implement IContent<T>
73-
[Singleton]
74-
public partial class Materials : IContent<Material>
84+
[ViewModel]
85+
public partial class UserViewModel : BaseViewModel
7586
{
76-
public Material[] All { get; } =
77-
[
78-
new("Steel", "Gray", 100),
79-
new("Wood", "Brown", 50),
80-
new("Gold", "Yellow", 25)
81-
];
87+
[Bind]
88+
private string _firstName = "";
89+
90+
[Bind]
91+
private string _lastName = "";
92+
93+
[Bind]
94+
private int _age;
8295
}
8396
```
8497

85-
The source generator automatically creates:
98+
Generated code includes proper `INotifyPropertyChanged` implementation:
8699

87100
```csharp
88-
// Generated enum
89-
public enum MaterialsType
101+
public string FirstName
90102
{
91-
Steel,
92-
Wood,
93-
Gold
103+
get => _firstName;
104+
set => SetProperty(ref _firstName, value);
94105
}
106+
```
95107

96-
// Generated helper methods
97-
public partial class Materials
108+
### Command with Parameters
109+
110+
Commands automatically support parameters:
111+
112+
```csharp
113+
[ViewModel]
114+
public partial class DocumentViewModel : BaseViewModel
98115
{
99-
public Material Get(MaterialsType type) => All[(int)type];
100-
public Material this[MaterialsType type] => All[(int)type];
101-
public Material GetById(int id) => All[id];
102-
public Material Steel => All[0];
103-
public Material Wood => All[1];
104-
public Material Gold => All[2];
116+
[Command]
117+
public void DeleteItem(object parameter)
118+
{
119+
if (parameter is string itemId)
120+
{
121+
// Delete logic here
122+
}
123+
}
105124
}
106125
```
107126

108-
Use the generated code:
127+
### Integration with Dependency Injection
109128

110-
```csharp
111-
var materials = host.Get<Materials>();
129+
SimpleMVVM works seamlessly with dependency injection containers:
112130

113-
// Type-safe access using enums
114-
var steel = materials[MaterialsType.Steel];
115-
var wood = materials.Get(MaterialsType.Wood);
131+
```csharp
132+
// Using SimpleInjection (companion package)
133+
[Singleton][ViewModel]
134+
public partial class MainViewModel : BaseViewModel
135+
{
136+
private readonly IDataService _dataService;
137+
138+
public MainViewModel(IDataService dataService)
139+
{
140+
_dataService = dataService;
141+
}
142+
143+
[Command]
144+
public async void LoadData()
145+
{
146+
var data = await _dataService.GetDataAsync();
147+
// Handle data
148+
}
149+
}
150+
```
116151

117-
// Direct property access
118-
var gold = materials.Gold;
152+
## How It Works
119153

120-
// Index-based access
121-
var firstMaterial = materials.GetById(0);
122-
```
154+
SimpleMVVM uses Roslyn source generators to analyze your code at compile time and automatically generate:
123155

124-
## Advanced Features
156+
1. **Command Classes**: Each `[Command]` method gets a corresponding `ICommand` implementation
157+
2. **Command Properties**: Properties that expose the commands for data binding
158+
3. **Observable Properties**: Properties with `INotifyPropertyChanged` support for `[Bind]` fields
125159

126-
### Performance Optimizations
160+
All generated code is available in IntelliSense and can be debugged normally.
127161

128-
The library includes `NamedComparer<T>` for efficient dictionary operations with `INamed` keys:
162+
## Generated Code Example
129163

164+
**Your Code:**
130165
```csharp
131-
// Use ToNamedDictionary extension method
132-
var materialDict = materials.All.ToNamedDictionary(m => m.Durability);
133-
134-
// Or explicitly specify the comparer
135-
var dict = new Dictionary<Material, int>(new NamedComparer<Material>());
166+
[ViewModel]
167+
public partial class MyViewModel : BaseViewModel
168+
{
169+
[Command]
170+
public void DoSomething() => Console.WriteLine("Done!");
171+
}
136172
```
137173

138-
### SubContent Collections
139-
140-
For hierarchical content organization:
141-
174+
**Generated Code:**
142175
```csharp
143-
public class WeaponStats : ISubContent<Material, int>
176+
public partial class MyViewModel
144177
{
145-
public Dictionary<Material, int> ByKey { get; }
146-
public int this[Material material] => ByKey[material];
178+
private DoSomethingCommand? _doSomethingCommand;
179+
public DoSomethingCommand DoSomethingCommand => _doSomethingCommand ??= new DoSomethingCommand(this);
180+
}
181+
182+
public sealed class DoSomethingCommand : BaseCommand
183+
{
184+
private readonly MyViewModel _viewModel;
185+
186+
public DoSomethingCommand(MyViewModel viewModel)
187+
{
188+
_viewModel = viewModel;
189+
}
190+
191+
public override void Execute(object? parameter)
192+
{
193+
_viewModel.DoSomething();
194+
}
147195
}
148196
```
149197

150-
### Roslyn Analyzers
198+
## Best Practices
199+
200+
1. **Inherit from BaseViewModel**: Always inherit from `BaseViewModel` for proper `INotifyPropertyChanged` support
201+
2. **Use Partial Classes**: Mark your view models as `partial` to allow source generation
202+
3. **Async Commands**: For async operations, use `async void` in command methods
203+
4. **Parameter Validation**: Always validate parameters in command methods
204+
5. **Dependency Injection**: Use constructor injection for services and dependencies
205+
206+
## Troubleshooting
207+
208+
### Generator Not Running
151209

152-
The package includes analyzers that help you:
153-
- **NC001**: Ensures `Dictionary<TKey, TValue>` uses `NamedComparer<T>` for `INamed` keys
154-
- **TND001**: Suggests using `ToNamedDictionary()` instead of `ToDictionary()` for `INamed` keys
210+
If the source generator isn't creating commands:
211+
212+
1. Ensure you have the `[ViewModel]` attribute on your class
213+
2. Make sure the class is marked as `partial`
214+
3. Verify you're inheriting from `BaseViewModel`
215+
4. Check that methods have the `[Command]` attribute
216+
5. Clean and rebuild your solution
217+
218+
### Missing Commands in XAML
219+
220+
If commands aren't appearing in XAML IntelliSense:
221+
222+
1. Rebuild the project to trigger source generation
223+
2. Check that the generated files are created (enable `<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>` to see them)
224+
3. Ensure proper namespace imports in XAML
155225

156226
## Requirements
157227

158228
- .NET 8.0 or .NET 9.0
159-
- C# with nullable reference types enabled (recommended)
229+
- Windows (WPF applications only)
230+
- C# 10.0 or later
160231

161-
## How It Works
232+
## License
162233

163-
1. **Service Discovery**: The host scans all loaded assemblies for classes marked with lifetime attributes
164-
2. **Dependency Resolution**: Constructor parameters are automatically resolved from registered services
165-
3. **Source Generation**: The generator scans for classes implementing `IContent<T>` and generates enums and helper methods
166-
4. **Code Analysis**: Roslyn analyzers ensure best practices for dictionary usage with named keys
234+
MIT License - see LICENSE file for details.
167235

168-
## Best Practices
236+
## Contributing
169237

170-
- Use `[Singleton]` for stateless services and shared resources
171-
- Use `[Scoped]` for services that should be unique per operation/request
172-
- Use `[Transient]` for lightweight, stateless services that need fresh instances
173-
- Always implement `INamed` for content objects to enable source generation
174-
- Use the generated enums for type-safe content access
175-
- Leverage `ToNamedDictionary()` for performance when working with `INamed` collections
238+
Contributions are welcome! Please feel free to submit issues and pull requests.
176239

177-
## License
240+
## Related Packages
178241

179-
MIT License - see the license file for details.
242+
- **SimpleInjection**: Companion dependency injection container with automatic service discovery

SimpleMVVM.Example/App.xaml

Lines changed: 0 additions & 9 deletions
This file was deleted.

SimpleMVVM.Example/App.xaml.cs

Lines changed: 0 additions & 14 deletions
This file was deleted.

SimpleMVVM.Example/AssemblyInfo.cs

Lines changed: 0 additions & 10 deletions
This file was deleted.

0 commit comments

Comments
 (0)