Saury.Revit.Template 1.3.4

dotnet new install Saury.Revit.Template@1.3.4
                    
This package contains a .NET Template Package you can call from the shell/command line.

Saury.Revit.Template

一个基于 MVVM 模式和依赖注入的 Revit 插件开发模板,同时支持 Revit 2024、Revit 2025、Revit 2026 和 Revit 2027。

特性

  • 多版本支持 - Debug_R24 / Release_R24 面向 Revit 2024,Debug_R25 / Release_R25 面向 Revit 2025,Debug_R26 / Release_R26 面向 Revit 2026,Debug_R27 / Release_R27 面向 Revit 2027
  • 对应运行时 - Revit 2024 使用 net48,Revit 2025 / 2026 使用 net8.0-windows,Revit 2027 使用 net10.0-windows
  • MVVM 架构 - 使用 CommunityToolkit.Mvvm 实现 Model-View-ViewModel 模式
  • 依赖注入 - 基于 Microsoft.Extensions.Hosting 的 DI 容器
  • 依赖加载兜底 - 正常解析失败时从插件目录加载依赖;.NET Framework 使用 Assembly.LoadFrom,现代 .NET 使用主插件所在的 AssemblyLoadContext
  • 薄命令入口 - RevitCommandBase 统一处理异常日志、执行结果和基础设施访问
  • Ribbon 分层 - Application 只负责生命周期,Ribbon 创建集中在 IApplicationUI
  • 泛型 Dialog 服务 - 支持 ShowDialog<TView>() 模态窗口和 Show<TView>() 唯一非模态窗口
  • Revit 上下文服务 - 插件启动时一次性注入 UIApplication,业务代码通过 IRevitContext 动态访问当前文档
  • 外部事件服务 - 内置单请求 RevitEventService,非模态 WPF 可安全封送操作到 Revit API 上下文
  • 独立 Data 项目 - 本地数据库基础设施放在 MyRevitPlugin.Data,主插件项目只通过 DI 引用
  • 独立 UI 项目 - MyRevitPlugin.Ui 集中提供主题令牌、控件样式、转换器和资源字典,业务窗口不重复维护视觉基础设施
  • 主题切换 - 内置浅色、深色和跟随 Windows 系统三种模式,已打开窗口和原生标题栏即时更新
  • 中英本地化 - 设置页、代码侧文本和 Revit Ribbon 共用同一份中英文资源,切换后立即生效
  • 本地 SQLite 数据库 - 基于 FreeSql,内置设置表、数据库初始化和备份服务
  • 常用 Revit 扩展 - 内置轻量 Transaction 和 Collector 辅助方法
  • 共享 Data 目录 - 所有 Revit 版本共用 %APPDATA%\MyRevitPlugin\Data,安装器可写入用户选择的数据目录
  • 日志系统 - LogProviderService 接入 Microsoft.Extensions.Logging,按日期写入共享 Data 目录下的 Logs\Saury.Revit.TemplateyyyyMMdd.log
  • MSI 安装器 - 内置 WixSharp per-user 安装器,支持版本选择、Revit 检测、运行阻断、升级和卸载时可选清除用户数据
  • 自动混淆 - Release 安装包构建自动使用 ConfuserEx2 混淆自有插件程序集,Debug 和日常插件构建不混淆
  • 自动替换 - 项目名称、命名空间、程序集名、addin 文件名和 GUID 自动生成替换
  • 自动部署 - 默认构建后复制到当前用户的 Revit Addins 目录,可用 -p:DeployToRevit=false 关闭
  • 完整示例 - 包含居中的竖向 SettingsView,演示 MVVM、主题、本地化、持久化和 Ribbon 联动

安装模板

dotnet new install Saury.Revit.Template

使用模板

创建新项目

dotnet new saury-revit -n MyRevitPlugin

构建 Revit 2024

dotnet build MyRevitPlugin.slnx --configuration Debug_R24

构建 Revit 2025

dotnet build MyRevitPlugin.slnx --configuration Debug_R24
dotnet build MyRevitPlugin.slnx --configuration Debug_R25

构建 Revit 2026

dotnet build MyRevitPlugin.slnx --configuration Debug_R26

构建 Revit 2027

dotnet build MyRevitPlugin.slnx --configuration Debug_R27

构建部署行为

dotnet build MyRevitPlugin.slnx --configuration Debug_R25
dotnet build MyRevitPlugin.slnx --configuration Debug_R26
dotnet build MyRevitPlugin.slnx --configuration Debug_R27

默认构建会部署。需要只编译不复制时:

dotnet build MyRevitPlugin.slnx --configuration Debug_R27 -p:DeployToRevit=false

部署目标使用当前 Windows 用户的 %APPDATA%,按构建配置自动选择:

Debug_R24 / Release_R24 -> %APPDATA%\Autodesk\Revit\Addins\2024\
Debug_R25 / Release_R25 -> %APPDATA%\Autodesk\Revit\Addins\2025\
Debug_R26 / Release_R26 -> %APPDATA%\Autodesk\Revit\Addins\2026\
Debug_R27 / Release_R27 -> %APPDATA%\Autodesk\Revit\Addins\2027\

构建 MSI 安装器

dotnet build MyRevitPlugin.Installer/MyRevitPlugin.Installer.csproj --configuration Release

Release 安装器构建会自动构建 Release_R24 / Release_R25 / Release_R26 / Release_R27 四套插件产物,并使用 ConfuserEx2 混淆自有程序集后打包 MSI。普通插件构建和 Debug 安装器构建不会混淆。

安装器输出:

MyRevitPlugin.Installer/Output/MyRevitPlugin-Setup-1.0.0.msi

默认混淆规则:

rename
ctrl flow
ref proxy
anti debug
anti dump
anti ildasm

constantsinvalid metadataanti tamperresourcestypescrambleharden 默认禁用。详见 Docs/编译混淆.md

卸载模板

dotnet new uninstall Saury.Revit.Template

项目结构

MyRevitPlugin/
├── MyRevitPlugin.slnx
├── MyRevitPlugin.Data/
│   ├── Compatibility/     # net48 编译器特性兼容 shim
│   ├── Configuration/     # 数据库配置、FreeSql 初始化、本地数据路径
│   ├── Entities/          # 模板级数据实体
│   ├── Extensions/        # AddLocalDataServices 注册入口
│   └── Services/
│       ├── Interfaces/    # 本地数据服务接口
│       ├── DatabaseBackupService.cs
│       └── PluginSettingService.cs
├── MyRevitPlugin.Ui/
│   ├── Controls/          # Button、Card、ComboBox、Switch、Slider 等控件样式
│   ├── Converters/        # 通用 WPF 转换器
│   ├── Enums/             # 实际视觉主题枚举
│   ├── Resources/         # 控件聚合字典和浅色/深色主题令牌
│   ├── ThemeManager.cs
│   └── MyRevitPlugin.Ui.csproj
├── MyRevitPlugin.Installer/
│   ├── MyRevitPlugin.Installer.csproj
│   └── build.cs           # WixSharp MSI authoring
├── MyRevitPlugin/
│   ├── Compatibility/     # net48 record/init/required 编译器特性兼容 shim
│   ├── Commands/          # Revit 命令适配
│   │   ├── RevitCommandBase.cs
│   │   └── SettingsCommand.cs
│   ├── Extensions/        # DI、Ribbon、Transaction、Collector 扩展
│   ├── Infrastructure/    # Revit 宿主、窗口、外部事件和日志基础设施
│   │   ├── Interfaces/
│   │   │   ├── IApplicationUI.cs
│   │   │   ├── IDialogService.cs
│   │   │   ├── IRevitContext.cs
│   │   │   └── IRevitEventService.cs
│   │   ├── ApplicationUI.cs
│   │   ├── DialogService.cs
│   │   ├── RevitContext.cs
│   │   ├── RevitEventService.cs
│   │   ├── WindowThemeHelper.cs
│   │   └── LogProviderService.cs
│   ├── Localization/      # XAML 动态资源与代码侧文本查询
│   ├── Models/            # UiPreferences、主题与语言枚举
│   ├── Services/          # UiSettingsService、SystemThemeWatcher
│   ├── ViewModels/        # SettingsViewModel
│   ├── Views/             # SettingsView
│   ├── Resources/         # Ribbon/窗口图标和中英文资源
│   ├── Host.cs            # Host 启停、日志、容器创建
│   └── Application.cs     # Revit 插件生命周期入口

MVVM 架构说明

Model

数据模型和业务逻辑,纯 C# 类。

public sealed class UiPreferences
{
    public string Theme { get; set; } = "Light";
    public string Language { get; set; } = "zh-CN";
}

ViewModel

继承 ObservableObject,使用 [ObservableProperty][RelayCommand]。需要访问 Revit 上下文时注入 IRevitContext,需要访问外部系统时优先抽接口,避免 ViewModel 直接依赖静态 API。

public sealed class SettingsViewModel : ObservableObject
{
    public SettingsViewModel(IUiSettingsService uiSettings)
    {
        SelectedTheme = uiSettings.ThemePreference;
        SelectedLanguage = uiSettings.Language;
    }

    public ThemePreference SelectedTheme { get; set; }
    public UiLanguage SelectedLanguage { get; set; }
}

View

XAML 界面通过构造函数注入 ViewModel。

public SettingsView(SettingsViewModel viewModel)
{
    InitializeComponent();
    DataContext = viewModel;
}

Command

命令继承 RevitCommandBaseUIApplication 已在插件启动时注入,基类只负责异常、日志和基础设施访问,并提供 DialogServiceRevitContextRevitEventService。具体命令只表达自身动作,不默认为每个命令创建 CommandHandler 和接口;只有当命令背后出现可复用业务流程时,再抽成独立 service。

protected override Result ExecuteCore(ExternalCommandData commandData, ref string message, ElementSet elements)
{
    DialogService.ShowDialog<SettingsView>();
    return Result.Succeeded;
}

Dialog

窗口由 DI 创建,Dialog 服务负责解析 View、设置 Revit 主窗口 owner 并显示窗口:

public interface IDialogService
{
    bool? ShowDialog<TView>() where TView : Window;
    void Show<TView>() where TView : Window;
}

Show<TView>() 会保证同类型非模态窗口只保留一个实例,并把窗口定位到 Revit 当前激活视图左上角。

ExternalEvent

非模态窗口不能直接调用 Revit API。打开非模态窗口的命令先初始化外部事件,再显示窗口:

protected override Result ExecuteCore(ExternalCommandData commandData, ref string message, ElementSet elements)
{
    RevitEventService.Initialize();
    DialogService.Show<MyView>();
    return Result.Succeeded;
}

ViewModel 注入 IRevitEventServiceIRevitContext,通过单请求外部事件执行 Revit 操作:

revitEventService.Run("更新模型", () =>
{
    var document = revitContext.ActiveDocument
        ?? throw new InvalidOperationException("当前没有打开的文档。");

    document.RunTransaction("更新模型", () =>
    {
        // Revit API 写操作
    });
}, ex => StatusText = $"执行失败:{ex.Message}");

同一时刻只允许一个请求等待或执行;后续请求会立即通过 onError 返回,不会在插件内部排队。

Ribbon

Application 不直接创建按钮。Ribbon UI 集中在 IApplicationUI / ApplicationUI,按钮通过 RibbonPanelExtensions.AddPushButton<TCommand>() 创建:

panel.AddPushButton<SettingsCommand>(
    uiSettings.GetText("Ribbon.Settings.Text"),
    uiSettings.GetText("Ribbon.Settings.ToolTip"),
    RibbonPanelExtensions.LoadResourceImage("Resources/Icons/setting.png"));

主题与本地化

  • MyRevitPlugin.Ui 只负责实际浅色/深色视觉资源和可复用控件,不依赖 Revit API。
  • UiSettingsService 是主题偏好、实际主题和界面语言的唯一业务状态源,设置保存在共享数据库的 ui.preferences 记录中。
  • SystemThemeWatcher 监听 Windows 应用主题,并把回调封送回 Revit UI Dispatcher。
  • LocalizationManager 同时服务 XAML DynamicResource、代码侧字符串和 Ribbon 文本;只修改 CurrentUICulture,不会改变数值输入解析使用的 CurrentCulture
  • DialogService 为窗口应用 Culture、主题标题栏和事件生命周期,设置页以 Revit 主窗口为 Owner 居中打开。
  • 新增窗口时合并 LocalizationDictionaryThemesDictionaryControlsDictionary,即可继承主题和语言切换能力。

依赖注入

主插件服务注册集中在 MyRevitPlugin/Extensions/ServiceCollectionExtensions.csHost.cs 只负责创建 Host 和日志:

builder.Services.AddRevitPluginServices(builder.Configuration);

基础设施实现集中在 Infrastructure,接口集中在 Infrastructure/Interfaces。后续新增业务服务时,默认实现放在 Services,接口放在 Services/Interfaces

日志

Host 使用 LogProviderService 接入标准 Microsoft.Extensions.Logging

builder.Logging.AddProvider(new LogProviderService(logDirectory));

业务代码继续注入 ILogger<T>,不直接依赖文件实现。日志按天写入共享 Data 目录的 Logs 子目录,并自动保留最近 14 个日志文件。

本地数据服务由 Data 项目提供统一入口:

services.AddLocalDataServices(configuration);

默认会注册 IFreeSqlIPluginSettingServiceIDatabaseBackupService。模板默认只引用 SQLite Provider;如果后续要切换 MySQL、PostgreSQL 或 SQL Server,需要在 Data 项目增加对应的 FreeSql.Provider.* 包,并在 appsettings.json 中配置连接字符串。

本地数据库

默认配置在 appsettings.json

{
  "Database": {
    "Provider": "Sqlite",
    "FileName": "MyRevitPlugin.db",
    "AutoSyncStructure": true,
    "EnableSqlLogging": false
  }
}

数据库默认创建在共享 Data 目录:

%APPDATA%\MyRevitPlugin\Data\MyRevitPlugin.db

MSI 安装器会把用户选择的数据目录写入 HKCU\Software\MyRevitPlugin\DataPath。插件启动时优先读取该注册表值;未安装或读不到注册表时回退到 %APPDATA%\MyRevitPlugin\Data

Data 项目只保留模板级基础设施。业务实体、仓储和领域服务应继续放在 MyRevitPlugin.Data 内扩展,避免把数据库实现耦合进 Revit UI/Command 项目。

技术栈

配置 Revit TargetFramework Revit API 包
Debug_R24 / Release_R24 2024 net48 Nice3point.Revit.Api.RevitAPI/UI 2024.3.40
Debug_R25 / Release_R25 2025 net8.0-windows Nice3point.Revit.Api.RevitAPI/UI 2025.4.50
Debug_R26 / Release_R26 2026 net8.0-windows Nice3point.Revit.Api.RevitAPI/UI 2026.4.10
Debug_R27 / Release_R27 2027 net10.0-windows Nice3point.Revit.Api.RevitAPI/UI 2027.1.0

通用依赖:

  • CommunityToolkit.Mvvm 8.4.2
  • Microsoft.Extensions.Hosting 9.0.4 for R24/R25/R26, 10.0.9 for R27
  • FreeSql / FreeSql.Provider.Sqlite 3.2.833
  • WixSharp / WixSharp.bin 1.26.0

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
1.3.4 95 7/12/2026
1.3.3 101 7/10/2026
1.0.1 339 1/11/2026
1.0.0 320 1/11/2026