HansCnc.Mvvm.SourceGenerators 0.1.0-preview4

This is a prerelease version of HansCnc.Mvvm.SourceGenerators.
dotnet add package HansCnc.Mvvm.SourceGenerators --version 0.1.0-preview4
                    
NuGet\Install-Package HansCnc.Mvvm.SourceGenerators -Version 0.1.0-preview4
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="HansCnc.Mvvm.SourceGenerators" Version="0.1.0-preview4">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="HansCnc.Mvvm.SourceGenerators" Version="0.1.0-preview4" />
                    
Directory.Packages.props
<PackageReference Include="HansCnc.Mvvm.SourceGenerators">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add HansCnc.Mvvm.SourceGenerators --version 0.1.0-preview4
                    
#r "nuget: HansCnc.Mvvm.SourceGenerators, 0.1.0-preview4"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package HansCnc.Mvvm.SourceGenerators@0.1.0-preview4
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=HansCnc.Mvvm.SourceGenerators&version=0.1.0-preview4&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=HansCnc.Mvvm.SourceGenerators&version=0.1.0-preview4&prerelease
                    
Install as a Cake Tool

HansCnc.Mvvm

CI Build

轻量级 WPF MVVM 框架:Roslyn 源生成器 + 对话框服务,基于 CommunityToolkit.Mvvm、Autofac、R3。

开发环境:Git 仓库根目录为 HansCnc.Mvvm/(本目录)。若 IDE 工作区打开的是外层文件夹,请在终端中 cd 到本目录再执行 git / dotnet。详见 CONTRIBUTING.md 与 AGENTS.md。

项目结构

项目 说明
HansCnc.Mvvm 核心抽象:IViewFor<T>、IActivatableViewModel、DialogViewModelAttribute
HansCnc.Mvvm.WPF WPF 实现:DialogService、DialogViewModelBase、WhenActivated、MainThreadHelper
HansCnc.Mvvm.SourceGenerators 共享生成器源码(.shproj)
HansCnc.Mvvm.SourceGenerators.Package NuGet 分析器包(Roslyn 4.0.1 ~ 5.0.0)
HansCnc.Mvvm.Samples 示例 WPF 应用
HansCnc.Mvvm.*.Tests 单元 / 集成测试(含 HansCnc.Mvvm.Integration.Tests)

安装

NuGet(应用项目)

<PackageReference Include="HansCnc.Mvvm" Version="0.0.2-preview1" />
<PackageReference Include="HansCnc.Mvvm.WPF" Version="0.0.2-preview1" />
<PackageReference Include="HansCnc.Mvvm.SourceGenerators" Version="0.0.2-preview1" />

WPF 应用还需 UseWPF、Autofac、R3 等(见下方依赖)。

本地仓库开发(示例 / 贡献者)

HansCnc.Mvvm.Samples 引用生成器项目以便调试:

<ProjectReference Include="..\HansCnc.Mvvm.SourceGenerators.Roslyn4120\HansCnc.Mvvm.SourceGenerators.Roslyn4120.csproj"
                  OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
<ProjectReference Include="..\HansCnc.Mvvm\HansCnc.Mvvm.csproj" />
<ProjectReference Include="..\HansCnc.Mvvm.WPF\HansCnc.Mvvm.WPF.csproj" />

消费方应用优先使用 NuGet 三件套;仅在修改生成器本身时使用 ProjectReference + OutputItemType="Analyzer"。

源生成器

[IViewFor<TViewModel>]

为 WPF 视图(partial 类)生成 IViewFor<TViewModel> 实现:

[IViewFor<HomeViewModel>]
public partial class HomeView : UserControl { }

生成内容:ViewModelProperty 依赖属性、ViewModel CLR 属性、BindingRoot 便捷属性。

ID 说明
HMVVM0001 [IViewFor] 标记的类必须为 partial(支持 Code Fix:添加 partial)
HMVVM0002 [DialogViewModel] 不得显式声明基类
HMVVM0003 [DialogViewModel] 标记的类必须为 partial(支持 Code Fix)
HMVVM0004 [IViewFor] 中的 ViewModel 类型无法解析
HMVVM0005 同一类型上存在多个 [IViewFor](例如多个 partial 声明各带属性)

设计时绑定

在 XAML 根元素绑定到 ViewModel(运行时由 DialogService 或代码赋值):

<UserControl ...
    DataContext="{Binding RelativeSource={RelativeSource Mode=Self}, Path=ViewModel}"
    d:DataContext="{d:DesignInstance Type=vm:HomeViewModel, IsDesignTimeCreatable=True}">

示例见 HansCnc.Mvvm.Samples/Views/。

[DialogViewModel<TInput, TResult>]

为对话框 ViewModel(partial 类、无显式基类)注入基类 DialogViewModelBase<TInput, TResult>:

[DialogViewModel<string, string>]
public partial class MyDialogViewModel
{
    public void Confirm()
    {
        ResultContext = MvvmDialogResult.Ok(UserInput);
        Ok();
    }
}

生成器只添加基类声明;属性、OkCommand / CancelCommand、生命周期与 IDialogViewModel 成员均由 DialogViewModelBase 提供。

ID 说明
HMVVM0002 不得显式声明基类
HMVVM0003 [DialogViewModel] 标记的类必须为 partial

对话框

注册(Autofac)

var builder = new ContainerBuilder();

builder.UseDialogService();
builder.RegisterDialog<MyDialogViewModel, MyDialogWindow>();

// 约定:FooDialogViewModel → FooDialogWindow(同一程序集)
builder.RegisterDialogsFromAssembly(typeof(MyDialogViewModel).Assembly);

使用

var result = dialogService.ShowDialog<MyDialogViewModel, string, string>("输入值");
if (result.Result)
    Console.WriteLine(result.ResultValue);

DialogService 通过 IViewFor<TViewModel>.ViewModel 绑定 ViewModel(不设置 Window.DataContext)。对话框窗口须实现 IViewFor<TViewModel>(推荐 [IViewFor<T>] + partial)。

窗口行为约定

主题 说明
Owner 已 Show 的当前活动窗口,或已加载的 MainWindow
居中 在 XAML 中设置 WindowStartupLocation="CenterOwner"(见 Samples)
ESC / 取消 Cancel() 或 RequestClose();可配合 IsCancel="True" 按钮
生命周期 OnDialogInitialized / Loaded / Closing / Closed;钩子内异常由服务记录日志,不中断关闭流程

DialogViewModelBase 提供 Input、ResultContext、Initialize、Ok() / Cancel() 及上述生命周期虚方法。确认前设置 ResultContext,再调用 Ok();取消调用 Cancel()。

视图激活(R3)

[IViewFor<HomeViewModel>]
public partial class HomeView : UserControl
{
    public HomeView()
    {
        this.WhenActivated(disposables =>
        {
            // 视图激活时的订阅
        });
    }
}

当 ViewModel 实现 IActivatableViewModel 时,WhenActivated 会在首次激活/全部停用时调用 HandleActivation / HandleDeactivation。

UI 线程(MainThreadHelper)

MainThreadHelper.Invoke(() => { /* UI 线程同步 */ });
await MainThreadHelper.InvokeAsync(() => { /* UI 线程异步 */ });
MainThreadHelper.BeginInvoke(() => { /* 投递到队列,避免重入 */ });
MainThreadHelper.DoEvents(); // 长同步操作中偶尔泵送消息
MainThreadHelper.VerifyAccess(); // 断言当前在 UI 线程

属性 UiDispatcher 暴露缓存的 WPF 调度器(避免与 System.Windows.Threading.Dispatcher 类型同名冲突)。

R3 流与 UI 线程

应用启动时配置 R3 的 WPF 调度(Samples 使用 R3Extensions.WPF):

// App.xaml.cs
WpfProviderInitializer.SetDefaultObservableSystem(
    ex => Log.Error(ex, ex.Message),
    DispatcherPriority.Background,
    Dispatcher);

命令式 UI 用 MainThreadHelper;Observable 流 用 ObserveOnUi / SubscribeOnUi:

this.WhenActivated(d =>
{
    ViewModel!.WhenAnyValue(vm => vm.Counter)
        .ObserveOnUi()
        .Subscribe(c => { /* UI 线程回调 */ })
        .DisposeWith(d);
});

// 或把流绑到 ViewModel 属性(无 OAPH):
ViewModel!.WhenAnyValue(vm => vm.Counter)
    .SubscribeOnUi(c => viewModel.CounterDescription = $"已计 {c} 次");

WPF 控件事件 → Observable 请使用 MvvmAIO.R3.SourceGenerators(FromEvents / FromRoutedEvents)。属性观察见 WhenAnyMixin;ReactiveUI 迁移见 docs/MIGRATION-REACTIVEUI.md。

构建与测试

.\build.ps1
dotnet build HansCnc.Mvvm.slnx -c Release
dotnet test HansCnc.Mvvm.slnx -c Release --no-build

WPF 与集成测试需在 Windows 上运行。升级 MvvmAIO.R3.SourceGenerators 见 docs/DEPENDENCIES.md。

稳定 API(预览期)

在 0.1.0 之前仍可能调整,但以下面为对外承诺的主契约:IViewFor / [IViewFor]、[DialogViewModel]、DialogViewModelBase、IDialogService、DialogService、WhenActivated、MainThreadHelper、MvvmDialogResult<T>、诊断 HMVVM0001–0005。详见 CONTRIBUTING.md 与 docs/MIGRATION.md。

核心特性

  • IViewFor 源生成器 — 消除 DependencyProperty 样板代码
  • DialogViewModel 源生成器 — 属性标记 + DialogViewModelBase 分工
  • DialogService — 类型安全的模态/非模态对话框
  • WhenActivated — 基于 R3 的视图生命周期
  • MainThreadHelper — UI 线程封送与 DoEvents
  • 多 Roslyn 版本 — 4.0.1 / 4.3.1 / 4.12.0 / 5.0.0

依赖

许可证

MIT

There are no supported framework assets in this package.

Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

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.1.0-preview4 85 5/27/2026
0.1.0-preview3 75 5/27/2026
0.1.0-preview2 79 5/27/2026
0.1.0-preview1 76 5/27/2026
0.0.2-preview1 76 5/26/2026
0.0.1-preview7 75 5/21/2026
0.0.1-preview6 78 5/18/2026
0.0.1-preview5 70 5/18/2026
0.0.1-preview4 68 5/17/2026