Skip to content

Commit 4a5d460

Browse files
authored
Feature Add Splat Registrations to IViewFor Generator (#289)
* Add Attribute Property * Add Splat registration support to IViewFor generator Introduces SplatRegistrationType to IViewFor attributes and source generator, enabling automatic registration of views for view models in Splat's service locator. Updates documentation, tests, and sample usage to demonstrate new registration options and extension method for bulk registration. * Reduce the use of string builder * Update IViewForGeneratorTests.FromIViewFor#ReactiveUI.ReactiveUISourceGeneratorsExtensions.g.verified.cs
1 parent 78e2e4c commit 4a5d460

File tree

22 files changed

+299
-18
lines changed

22 files changed

+299
-18
lines changed

README.md

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,23 @@ ReactiveUI Source Generators automatically generate ReactiveUI objects to stream
3838
- `[ReactiveCommand(OutputScheduler = nameof(_isheduler))]` using a Scheduler defined in the class
3939
- `[ReactiveCommand][property: AttributeToAddToCommand]` with Attribute passthrough
4040
- `[IViewFor(nameof(ViewModelName))]`
41+
- `[IViewFor<YourViewModelType>]`
42+
- `[IViewFor("YourNameSpace.YourGenericViewModel<int>")]` Generic
43+
- `[IViewFor<YourViewModelType>(RegistrationType = SplatRegistrationType.PerRequest)]` with Splat Registration Type for IViewFor registration.
44+
- `[IViewFor<YourViewModelType>(RegistrationType = SplatRegistrationType.LazySingleton)]` Generic with Splat Registration Type for IViewFor registration.
45+
- `[IViewFor<YourViewModelType>(RegistrationType = SplatRegistrationType.Constant)]` Generic with Splat Registration Type for IViewFor registration.
4146
- `[RoutedControlHost("YourNameSpace.CustomControl")]`
4247
- `[ViewModelControlHost("YourNameSpace.CustomControl")]`
4348
- `[BindableDerivedList]` Generates a derived list from a ReadOnlyObservableCollection backing field
4449
- `[ReactiveCollection]` Generates property changed notifications on add, remove, new actions on a ObservableCollection backing field
4550

51+
#### IViewFor Registration generator
52+
53+
To register all views for view models registered via the IViewFor Source Generator with a specified `RegistrationType`, call the following method during application startup:
54+
```csharp
55+
Splat.Locator.CurrentMutable.RegisterViewsForViewModelsSourceGenerated();
56+
```
57+
4658
### Compatibility Notes
4759
- For ReactiveUI versions **older than V19.5.31**, all `[ReactiveCommand]` options are supported except for async methods with a `CancellationToken`.
4860
- For **.NET Framework 4.8 and older**, add [Polyfill by Simon Cropp](https://github.com/SimonCropp/Polyfill) or [PolySharp by Sergio Pedri](https://github.com/Sergio0694/PolySharp) to your project and set the `LangVersion` to 12.0 or later in your project file.
@@ -63,11 +75,17 @@ Generates read-only properties backed by an `ObservableAsPropertyHelper` based o
6375
Generates commands, with options to add attributes or enable `CanExecute` functionality.
6476

6577
### `[IViewFor]`
66-
Links a view to a view model for data binding.
78+
Links a view to a view model for data binding. Supports generic types and Splat registration.
6779

6880
### `[RoutedControlHost]` and `[ViewModelControlHost]`
6981
Platform-specific attributes for control hosting in WinForms applications.
7082

83+
### `[BindableDerivedList]`
84+
Generates a derived list from a `ReadOnlyObservableCollection` backing field.
85+
86+
### `[ReactiveCollection]`
87+
Generates property changed notifications on add, remove, and new actions on an `ObservableCollection` backing field.
88+
7189
## Historical Approach
7290

7391
### Read-Write Properties
@@ -525,6 +543,35 @@ The class must inherit from a UI Control from any of the following platforms and
525543
- Avalonia (Avalonia)
526544
- Uno (Windows.UI.Xaml).
527545

546+
### IViewFor with Splat Registration Type
547+
548+
Choose from the following Splat Registration Types:
549+
- `SplatRegistrationType.PerRequest`
550+
- `SplatRegistrationType.LazySingleton`
551+
- `SplatRegistrationType.Constant`
552+
- `SplatRegistrationType.None` (Default if not specified - no registration is performed)
553+
554+
```csharp
555+
using ReactiveUI.SourceGenerators;
556+
using Splat;
557+
[IViewFor<MyReactiveClass>(RegistrationType = SplatRegistrationType.PerRequest)]
558+
public partial class MyReactiveControl : UserControl
559+
{
560+
public MyReactiveControl()
561+
{
562+
InitializeComponent();
563+
ViewModel = Locator.Current.GetService<MyReactiveClass>();
564+
}
565+
}
566+
```
567+
568+
this will generate the following code to enable you register the marked Views as `IViewFor<ViewModel>` with Splat:
569+
```csharp
570+
using ReactiveUI.SourceGenerators;
571+
572+
Splat.Locator.CurrentMutable.RegisterViewsForViewModelsSourceGenerated();
573+
```
574+
528575
### Usage IViewFor with ViewModel Name - Generic Types should be used with the fully qualified name, otherwise use nameof(ViewModelTypeName)
529576
```csharp
530577
using ReactiveUI.SourceGenerators;

src/Directory.Packages.props

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
<PackageVersion Include="Nerdbank.GitVersioning" Version="3.8.118" />
1010
<PackageVersion Include="NuGet.Common" Version="6.14.0" />
1111
<PackageVersion Include="NuGet.Protocol" Version="6.14.0" />
12+
<PackageVersion Include="Splat" Version="16.0.1" />
1213
<PackageVersion Include="stylecop.analyzers" Version="1.2.0-beta.556" />
1314
<PackageVersion Include="Roslynator.Analyzers" Version="4.14.0" />
1415
<PackageVersion Include="ReactiveUI" Version="21.0.1" />
@@ -45,4 +46,4 @@
4546
<PackageVersion Include="Basic.Reference.Assemblies.Net80" Version="1.8.3" />
4647
<PackageVersion Include="Basic.Reference.Assemblies.Net80Windows" Version="1.8.3" />
4748
</ItemGroup>
48-
</Project>
49+
</Project>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//HintName: ReactiveUI.ReactiveUISourceGeneratorsExtensions.g.cs
2+
// <auto-generated/>
3+
#pragma warning disable
4+
#nullable enable
5+
6+
using global::ReactiveUI;
7+
using global::Splat;
8+
9+
namespace ReactiveUI.SourceGenerators
10+
{
11+
/// <summary>
12+
/// Source-generated registration extensions for ReactiveUI views.
13+
/// </summary>
14+
internal static class ReactiveUISourceGeneratorsExtensions
15+
{
16+
public static void RegisterViewsForViewModelsSourceGenerated(this global::Splat.IMutableDependencyResolver resolver)
17+
{
18+
if (resolver is null) throw new global::System.ArgumentNullException(nameof(resolver));
19+
}
20+
}
21+
}
22+
#nullable restore
23+
#pragma warning restore

src/ReactiveUI.SourceGenerator.Tests/IVIEWFOR/IViewForGeneratorTests.FromIViewFor#ReactiveUI.SourceGenerators.IViewForAttribute.g.verified.cs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,14 @@ namespace ReactiveUI.SourceGenerators;
1818
/// </remarks>
1919
/// <param name="viewModelType">Type of the view model.</param>
2020
[global::System.AttributeUsage(global::System.AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
21-
internal sealed class IViewForAttribute<T> : global::System.Attribute;
21+
internal sealed class IViewForAttribute<T> : global::System.Attribute
22+
{
23+
/// <summary>
24+
/// Gets the Splat registration type for Splat registration.
25+
/// Registers IViewFor<T> in the Splat service locator.
26+
/// </summary>
27+
public SplatRegistrationType RegistrationType { get; init; } = SplatRegistrationType.None;
28+
}
2229

2330
/// <summary>
2431
/// IViewForAttribute.
@@ -27,8 +34,15 @@ internal sealed class IViewForAttribute<T> : global::System.Attribute;
2734
/// <remarks>
2835
/// Initializes a new instance of the <see cref="IViewForAttribute"/> class.
2936
/// </remarks>
30-
/// <param name="viewModelType">Type of the view model.</param>
37+
/// <param name="viewModelType">Type of the view model, ensure to use the full type name including namespace.</param>
3138
[global::System.AttributeUsage(global::System.AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
32-
internal sealed class IViewForAttribute(string? viewModelType) : global::System.Attribute;
39+
internal sealed class IViewForAttribute(string? viewModelType) : global::System.Attribute
40+
{
41+
/// <summary>
42+
/// Gets the Splat registration type for Splat registration.
43+
/// Registers IViewFor<T> in the Splat service locator.
44+
/// </summary>
45+
public SplatRegistrationType RegistrationType { get; init; } = SplatRegistrationType.None;
46+
}
3347
#nullable restore
3448
#pragma warning restore

src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePartialProperties#ReactiveUI.SourceGenerators.AccessModifier.g.verified.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,13 @@ internal enum InheritanceModifier
3333
Override,
3434
New,
3535
}
36+
37+
internal enum SplatRegistrationType
38+
{
39+
None,
40+
LazySingleton,
41+
Constant,
42+
PerRequest,
43+
}
3644
#nullable restore
3745
#pragma warning restore

src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactiveProperiesWithAttributes#ReactiveUI.SourceGenerators.AccessModifier.g.verified.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,13 @@ internal enum InheritanceModifier
3333
Override,
3434
New,
3535
}
36+
37+
internal enum SplatRegistrationType
38+
{
39+
None,
40+
LazySingleton,
41+
Constant,
42+
PerRequest,
43+
}
3644
#nullable restore
3745
#pragma warning restore

src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactiveProperties#ReactiveUI.SourceGenerators.AccessModifier.g.verified.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,13 @@ internal enum InheritanceModifier
3333
Override,
3434
New,
3535
}
36+
37+
internal enum SplatRegistrationType
38+
{
39+
None,
40+
LazySingleton,
41+
Constant,
42+
PerRequest,
43+
}
3644
#nullable restore
3745
#pragma warning restore

src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesCalledValue#ReactiveUI.SourceGenerators.AccessModifier.g.verified.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,13 @@ internal enum InheritanceModifier
3333
Override,
3434
New,
3535
}
36+
37+
internal enum SplatRegistrationType
38+
{
39+
None,
40+
LazySingleton,
41+
Constant,
42+
PerRequest,
43+
}
3644
#nullable restore
3745
#pragma warning restore

src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithAccess#ReactiveUI.SourceGenerators.AccessModifier.g.verified.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,13 @@ internal enum InheritanceModifier
3333
Override,
3434
New,
3535
}
36+
37+
internal enum SplatRegistrationType
38+
{
39+
None,
40+
LazySingleton,
41+
Constant,
42+
PerRequest,
43+
}
3644
#nullable restore
3745
#pragma warning restore

src/ReactiveUI.SourceGenerator.Tests/REACTIVE/ReactiveGeneratorTests.FromReactivePropertiesWithAttributesAccessAndInheritance#ReactiveUI.SourceGenerators.AccessModifier.g.verified.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,13 @@ internal enum InheritanceModifier
3333
Override,
3434
New,
3535
}
36+
37+
internal enum SplatRegistrationType
38+
{
39+
None,
40+
LazySingleton,
41+
Constant,
42+
PerRequest,
43+
}
3644
#nullable restore
3745
#pragma warning restore

0 commit comments

Comments
 (0)