HansCnc.Core 0.3.0-preview1

This is a prerelease version of HansCnc.Core.
dotnet add package HansCnc.Core --version 0.3.0-preview1
                    
NuGet\Install-Package HansCnc.Core -Version 0.3.0-preview1
                    
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.Core" Version="0.3.0-preview1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="HansCnc.Core" Version="0.3.0-preview1" />
                    
Directory.Packages.props
<PackageReference Include="HansCnc.Core" />
                    
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.Core --version 0.3.0-preview1
                    
#r "nuget: HansCnc.Core, 0.3.0-preview1"
                    
#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.Core@0.3.0-preview1
                    
#: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.Core&version=0.3.0-preview1&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=HansCnc.Core&version=0.3.0-preview1&prerelease
                    
Install as a Cake Tool

HansCnc.Mvvm

CI Build

轻量级 WPF MVVM 框架:Roslyn 源生成器 + 对话框服务,基于 CommunityToolkit.MvvmAutofacR3

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

项目结构

项目 说明
HansCnc.Core 领域标记接口(IModel / IDto / IEntity 等),NuGet HansCnc.Core
HansCnc.DataCollection 数据采集运行时 + NotifyList<T>,NuGet HansCnc.DataCollection
HansCnc.Mvvm MVVM 核心 + 内置 Roslyn 源生成器(含 DataCollection 节点/根生成器)
HansCnc.Mvvm.WPF WPF 实现:DialogServiceDialogViewModelBaseWhenActivatedMainThreadHelper
HansCnc.Mvvm.SourceGenerators 共享生成器源码(仓库内;已打包进 HansCnc.Mvvm NuGet)
HansCnc.Mvvm.SourceGenerators.Package 历史打包布局参考(不再单独发布
HansCnc.Mvvm.Samples 示例 WPF 应用
HansCnc.Mvvm.*.Tests 单元 / 集成测试(含 HansCnc.Mvvm.Integration.Tests

安装

NuGet(应用项目)

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

完整版说明(HTML,随发布更新):docs/DOCUMENTATION.html。全量变更记录:docs/CHANGELOG-HISTORY.md

HansCnc.Mvvm 已包含 Roslyn 分析器(analyzers/dotnet/roslyn*/cs),无需再引用 HansCnc.Mvvm.SourceGenerators

WPF 应用还需 UseWPF、Autofac、R3 等(见下方依赖)。从旧版三件套迁移见 MIGRATION.md

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

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 四包HansCnc.CoreHansCnc.DataCollectionHansCnc.MvvmHansCnc.Mvvm.WPF;WPF 应用通常显式引用后两者,DataCollection 可由 HansCnc.Mvvm 传递依赖)。启用实时数据采集时导入 HansCnc.Mvvm.DataCollection.props(来自 HansCnc.DataCollection 包)。仅在修改生成器本身时使用 ProjectReference + OutputItemType="Analyzer"

集合类型

类型 程序集 / 命名空间 通知 典型用途
NotifyList<T> HansCnc.DataCollection 自定义 CollectionChanged(细粒度) ViewModel 内逻辑集合
ObservableDictionary<TKey, TValue> HansCnc.Mvvm / HansCnc.Collections BCL INotifyCollectionChanged + INotifyPropertyChanged WPF XAML 绑定

ObservableDictionaryNotifyList 不同,专为 WPF 绑定契约设计。在 UI 线程上修改;SyncRoot 提供线程安全,不替代 Dispatcher。

public ObservableDictionary<string, string> Items { get; } = new();

<ItemsControl ItemsSource="{Binding Items}" />

<TextBlock Text="{Binding Items[TitleKey]}" />

源生成器

[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 声明各带属性)

[EditableModel] / [DirtyPart] / [DirtyCollectionPart]

为可编辑实体(partial + ObservableObject)生成 IEditableModel 脏跟踪成员:DirtyContextDirtyCountIsDirtySetDirtyClearDirtyRaiseDirtyChanged。嵌套图用 [DirtyPart](引用)与 [DirtyCollectionPart]IEnumerable<T>T 须实现 IEditableModel 或标记 [EditableModel])。

[EditableModel]
public partial class Article : ObservableObject
{
    [DirtyPart]
    public Author Author { get; set; } = new();

    [DirtyCollectionPart]
    public List<Tag> Tags { get; set; } = [];
}

脏标记由业务代码显式调用 SetDirty(生成器不会挂钩属性 setter)。示例见 HansCnc.Mvvm.Samples/EditableModels/

ID 说明
HMVVM0006 [EditableModel] 标记的类必须为 partial(支持 Code Fix)
HMVVM0007 [EditableModel] 类型必须继承 ObservableObject
HMVVM0008 [DirtyPart] 属性类型须实现 IEditableModel(或带 [EditableModel]
HMVVM0009 [DirtyCollectionPart] 须为 IEnumerable<T>T 满足同上

设计时绑定

在 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 提供 InputResultContextInitializeOk() / 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 用 MainThreadHelperObservable 流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.SourceGeneratorsFromEvents / FromRoutedEvents)。属性观察见 WhenAnyMixin;ReactiveUI 迁移见 docs/MIGRATION-REACTIVEUI.md

文档

文件 说明
docs/DOCUMENTATION.html 当前发布版本的完整使用文档(单文件 HTML)
docs/CHANGELOG-HISTORY.md 全部历史版本变更记录
docs/README.md 发布时如何同步更新上述两份文档

构建与测试

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

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

稳定 API(预览期)

0.1.0 之前仍可能调整,但以下面为对外承诺的主契约:IViewFor / [IViewFor][DialogViewModel]DialogViewModelBaseIDialogServiceDialogServiceWhenActivatedMainThreadHelperMvvmDialogResult<T>、诊断 HMVVM0001–0005。详见 CONTRIBUTING.mddocs/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

Product 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 is compatible.  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 is compatible.  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 is compatible. 
.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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.0

    • No dependencies.
  • .NETStandard 2.1

    • No dependencies.
  • net10.0

    • No dependencies.
  • net8.0

    • No dependencies.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on HansCnc.Core:

Package Downloads
HansCnc.DataCollection

Real-time data collection runtime (attributes, IDataCollectionObject, NotifyList) for HansCnc MVVM apps.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.3.0-preview1 65 6/4/2026