HansCnc.Mvvm.SourceGenerators
0.1.0-preview4
dotnet add package HansCnc.Mvvm.SourceGenerators --version 0.1.0-preview4
NuGet\Install-Package HansCnc.Mvvm.SourceGenerators -Version 0.1.0-preview4
<PackageReference Include="HansCnc.Mvvm.SourceGenerators" Version="0.1.0-preview4"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
<PackageVersion Include="HansCnc.Mvvm.SourceGenerators" Version="0.1.0-preview4" />
<PackageReference Include="HansCnc.Mvvm.SourceGenerators"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
paket add HansCnc.Mvvm.SourceGenerators --version 0.1.0-preview4
#r "nuget: HansCnc.Mvvm.SourceGenerators, 0.1.0-preview4"
#:package HansCnc.Mvvm.SourceGenerators@0.1.0-preview4
#addin nuget:?package=HansCnc.Mvvm.SourceGenerators&version=0.1.0-preview4&prerelease
#tool nuget:?package=HansCnc.Mvvm.SourceGenerators&version=0.1.0-preview4&prerelease
HansCnc.Mvvm
轻量级 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
依赖
- CommunityToolkit.Mvvm — MVVM 基元
- Autofac — IoC 容器
- R3 — 响应式扩展
- R3Extensions.WPF — WPF 调度(
HansCnc.Mvvm.WPF在 net472+ 引用;应用启动建议WpfProviderInitializer) - MvvmAIO.R3.SourceGenerators — WPF 事件源生成(
HansCnc.Mvvm.WPF内部使用;应用侧同样可用) - Serilog — 日志(
HansCnc.Mvvm.WPF可选)
许可证
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 |