Vetuviem.SourceGenerator
0.14.4
dotnet add package Vetuviem.SourceGenerator --version 0.14.4
NuGet\Install-Package Vetuviem.SourceGenerator -Version 0.14.4
<PackageReference Include="Vetuviem.SourceGenerator" Version="0.14.4" />
<PackageVersion Include="Vetuviem.SourceGenerator" Version="0.14.4" />
<PackageReference Include="Vetuviem.SourceGenerator" />
paket add Vetuviem.SourceGenerator --version 0.14.4
#r "nuget: Vetuviem.SourceGenerator, 0.14.4"
#:package Vetuviem.SourceGenerator@0.14.4
#addin nuget:?package=Vetuviem.SourceGenerator&version=0.14.4
#tool nuget:?package=Vetuviem.SourceGenerator&version=0.14.4
Vetuviem
Vetuviem is a toolkit to support View to View Model binding (MVVM → V2VM → Ve-Tu-Viem) aimed at offering a structure to get more re-usability out of ReactiveUI.
Mission Statement
- To give a mechanism to reduce the amount of boiler plate code being produced, by allowing some of the ReactiveUI specific logic to be hidden away
- Allow the developer to think along the lines of standard behaviours for controls by offering a way to produce re-usable behaviours through a class and\or function design pattern
- Allow the developer to focus on what matters on the ViewModel
- Reduce the cognitive load by
- Removing the risk of misusing 1 way or 2 way binding
- Remove the need for the user to think about having to cater for Bind vs BindCommand
- Offer a structure that allows for more work to be done potentially with Source Generators to reduce reflection and improve the build time developer experience.
Current Status
This is currently a proof of concept alpha. For understanding of the design reasoning please see https://www.dpvreony.com/articles/designing-vetuviem/
Nuget Packages
| Purpose | Package | NuGet |
|---|---|---|
| Command Line Generation | Coming soon | Coming Soon |
| Visual Studio Integration | Vetuviem.SourceGenerator | |
| Core Functionality | Vetuviem.Core |
Getting started
Install the desired package
TODO
Add workaround for Windows based builds
On CI runners you can occasionally find that the Source generators fail to load with soemthing along the lines of ErrorCode: ReferencesNewerCompiler, ReferencedCompilerVersion: 5.0.0.0.
NOTE: different .NET SDK or MSBuild versions are inconsistent with the error message, you may sometimes see it prefixed with ADR0001 or CS9057, other times it has no prefix.
This is currently (as of 2026-01) an issue with Github Actions where Visual Studio 2022 is on the Agent. This forces MSBuild to use the desired version rather than the one built into Visual Studio and MSBuild.
Place the following in a Dir.Build.Props file or the relevant C# project file(s).
<PropertyGroup>
<UseSharedCompilation>false</UseSharedCompilation>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Net.Compilers.Toolset" Version="5.0.0" Condition="'$(MSBuildRuntimeType)' != 'Core'">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
An example
Currently to write binding logic in the codebehind you have to write something similar to this for a single control
// Traditional ReactiveUI binding approach
this.WhenActivated(disposables =>
{
this.Bind(ViewModel, vm => vm.Forename, v => v.Forename.Text)
.DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.ForenameLengthRemaining, v => v.ForenameLengthRemaining.Content)
.DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.ForenameLengthRemaining, v => v.ForenameLengthRemaining.Foreground,
lengthRemaining => GetBrushForLengthRemaining(lengthRemaining))
.DisposeWith(disposables);
});
But what if you have a way to simplify logic and offer a way to even make it reusable without all the boilerplate leg work?
// Vetuviem approach using ViewBindingModels
public sealed class QuestionnaireViewBindingModels : AbstractEnableViewToViewModelBindings<QuestionnaireView, QuestionnaireViewModel>
{
protected override IEnumerable<IControlBindingModel<QuestionnaireView, QuestionnaireViewModel>> GetBindings()
{
yield return new TextBoxControlBindingModel<QuestionnaireView, QuestionnaireViewModel>(vw => vw.Forename)
{
Text = new TwoWayBinding<QuestionnaireViewModel, string>(vm => vm.Forename),
};
yield return new LabelControlBindingModel<QuestionnaireView, QuestionnaireViewModel>(vw => vw.ForenameLengthRemaining)
{
Content = new OneWayBindingOnOneOrTwoWayBind<QuestionnaireViewModel, object>(vm => vm.ForenameLengthRemaining, o => o?.ToString() ?? string.Empty),
Foreground = new OneWayBindingWithConversionOnOneOrTwoWayBind<QuestionnaireViewModel, Brush, int>(vm => vm.ForenameLengthRemaining, lengthRemaining => GetBrushForLengthRemaining(lengthRemaining))
};
}
}
Configuration
Vetuviem source generators can be configured through MSBuild properties in your project file (.csproj). Add these properties to a <PropertyGroup> section to customize code generation behavior.
Available Properties
| Property | Description | Default Value |
|---|---|---|
Vetuviem_Root_Namespace |
Override the root namespace for generated code | (Project's root namespace) |
Vetuviem_Make_Classes_Public |
Make generated classes public instead of internal | false |
Vetuviem_Assemblies |
Comma-separated list of assemblies to scan for controls | (Platform-specific defaults) |
Vetuviem_Assembly_Mode |
How to use custom assemblies: Replace or Extend |
Replace |
Vetuviem_Base_Namespace |
Base namespace when using custom assemblies | (none) |
Vetuviem_Include_Obsolete_Items |
Include properties marked with ObsoleteAttribute |
false |
Vetuviem_Allow_Experimental_Properties |
Include properties marked with ExperimentalAttribute |
false |
Vetuviem_Logging_Implementation_Mode |
Logging implementation: None or SplatViaServiceLocator |
SplatViaServiceLocator |
Property Details
Vetuviem_Root_Namespace
Override the default root namespace for generated code. This is useful when you want generated binding models to reside in a specific namespace.
Example:
<PropertyGroup>
<Vetuviem_Root_Namespace>MyApp.Generated</Vetuviem_Root_Namespace>
</PropertyGroup>
Vetuviem_Make_Classes_Public
Controls the visibility of generated binding model classes. By default, classes are generated as internal. Set this to true to make them public.
Example:
<PropertyGroup>
<Vetuviem_Make_Classes_Public>true</Vetuviem_Make_Classes_Public>
</PropertyGroup>
Vetuviem_Assemblies
Specify a comma-separated list of assemblies to scan for control types. Use in conjunction with Vetuviem_Assembly_Mode to either replace or extend the default platform assemblies.
Example:
<PropertyGroup>
<Vetuviem_Assemblies>CustomControls.dll,ThirdPartyControls.dll</Vetuviem_Assemblies>
</PropertyGroup>
Vetuviem_Assembly_Mode
Determines how the assemblies specified in Vetuviem_Assemblies are used:
Replace(default): Replace platform defaults with your custom assembliesExtend: Add custom assemblies in addition to platform defaults
Example:
<PropertyGroup>
<Vetuviem_Assembly_Mode>Extend</Vetuviem_Assembly_Mode>
</PropertyGroup>
Vetuviem_Base_Namespace
Used with custom assemblies to specify a base namespace. This allows third parties to use the generator and produce custom namespaces that inherit from the root or use a custom namespace.
Example:
<PropertyGroup>
<Vetuviem_Base_Namespace>MyCompany.Controls</Vetuviem_Base_Namespace>
</PropertyGroup>
Vetuviem_Include_Obsolete_Items
Controls whether properties marked with ObsoleteAttribute are included in code generation. By default, obsolete items are excluded.
Example:
<PropertyGroup>
<Vetuviem_Include_Obsolete_Items>true</Vetuviem_Include_Obsolete_Items>
</PropertyGroup>
Vetuviem_Allow_Experimental_Properties
Starting with .NET 10, properties can be marked with ExperimentalAttribute to indicate they are experimental APIs. This property controls how these are handled:
When false or not set (default):
- Properties marked with
ExperimentalAttributeare excluded from code generation - No warnings are generated
- Experimental properties are silently skipped
- Ensures backward compatibility
When true:
- Properties marked with
ExperimentalAttributeare included in code generation - A
SuppressMessageattribute is automatically added to suppress experimental warnings - The diagnostic ID from the
ExperimentalAttributeis extracted and used in the suppression
Example:
<PropertyGroup>
<Vetuviem_Allow_Experimental_Properties>true</Vetuviem_Allow_Experimental_Properties>
</PropertyGroup>
Example Control Property:
[Experimental("WFDEV001")]
public ThemeMode ThemeMode { get; set; }
Generated Binding Property (when enabled):
[SuppressMessage("Usage", "WFDEV001")]
public IOneOrTwoWayBind<TViewModel, ThemeMode>? ThemeMode { get; init; }
Notes:
- The diagnostic ID is read from the first constructor argument of
ExperimentalAttribute - Only properties with
publicaccessibility are considered for generation (standard behavior)
Vetuviem_Logging_Implementation_Mode
Controls the logging implementation generated in binding code:
None: No logging implementationSplatViaServiceLocator(default): Uses Splat logging via service locator
Example:
<PropertyGroup>
<Vetuviem_Logging_Implementation_Mode>None</Vetuviem_Logging_Implementation_Mode>
</PropertyGroup>
Support
For support, please:
- Check the design article for understanding the design reasoning
- Report bugs or request features via GitHub Issues
- Ask questions in GitHub Discussions
- Review the sample applications in the
srcdirectory for practical examples
Contribute
Contributions are welcome! Please:
- Read the Code of Conduct
- Fork the repository and create a feature branch
- Write tests for your changes
- Ensure all tests pass and code follows the existing style
- Submit a Pull Request with a clear description of your changes
License
This project is licensed under the MIT License - see the LICENSE file for details.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Microsoft.CodeAnalysis.CSharp (>= 5.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.14.4 | 2,318 | 3/5/2026 |
| 0.14.1 | 164 | 3/2/2026 |
| 0.13.7 | 837 | 2/23/2026 |
| 0.13.1 | 187 | 1/15/2026 |
| 0.12.19 | 172 | 1/1/2026 |
| 0.12.16 | 190 | 12/12/2025 |
| 0.12.15 | 497 | 12/10/2025 |
| 0.11.14 | 475 | 9/2/2025 |
| 0.11.2 | 405 | 6/28/2025 |
| 0.11.1 | 191 | 6/27/2025 |
| 0.10.102 | 216 | 6/21/2025 |
| 0.10.101 | 173 | 6/20/2025 |
| 0.10.100 | 173 | 6/20/2025 |
| 0.10.88 | 320 | 5/17/2025 |
| 0.10.67 | 665 | 1/18/2025 |
| 0.10.18 | 862 | 6/14/2024 |
| 0.10.17 | 242 | 6/14/2024 |
| 0.10.15 | 241 | 6/12/2024 |
| 0.10.12 | 244 | 6/9/2024 |
| 0.10.11 | 252 | 6/5/2024 |