网友作品 #000090 · 提交于 2026/08/10
Excel自定义函数插件:共享缓存实时联动重算



1 / 3
作品简介
这是作者「wps-udf-live-cache」蓝图成果:一个基于 Excel-DNA 的自定义函数插件,同时兼容 Excel 与 WPS 双宿主。它解决的经典问题是“先拉全量、再定时拉增量、多个公式共享同一份缓存”:由一个信号函数(LIVE_CACHE_SIGNAL)负责轮询数据源并推送修订信号,其余汇总公式把该信号作为依赖参数,借助 Excel 依赖链自动触发重算。
数据源支持内建 Demo 模拟与真实 HTTP 接口两种模式,改配置即可切换,并支持运行时热重载;同一插件可按频道隔离多路数据(如订单、库存、客户),各自拥有独立缓存与轮询周期。
核心亮点
- 信号驱动精确重算:不是定时刷新全部公式,而是缓存真的变化时才重算依赖它的公式,大工作簿性能更稳
- 全量+增量同步:首次全量拉取建缓存,之后按主键与时间戳做 upsert/delete,增量更旧自动忽略、支持删除标记
- 共享缓存省请求:同频道所有函数共享一份内存表,由统一轮询任务管理,下游读取零额外网络开销
- 多频道隔离:订单、库存、客户等不同数据源各自独立缓存、独立轮询周期与 HTTP 端点
- 零代码切换数据源:Demo 模拟与真实 HTTP 接口通过 JSON 配置切换,支持 CFG_RELOAD 热重载
- 工作簿状态持久化:通过 CustomXMLParts 把缓存快照写入工作簿,重开可查看,便于审计追溯
- 函数配套齐全:信号、状态查看、分组汇总(SUM/QTY/TABLE)、查询句柄、配置读取等函数一应俱全
技术与工具
- 运行时与框架:.NET 6 + Excel-DNA 1.9,x86/x64 双 xll 自动适配 Excel/WPS 宿主
- 响应式信号:System.Reactive(Rx.NET)的 BehaviorSubject 推送修订信号,配合 ExcelAsyncUtil.Observe
- 并发与缓存:DataTable + ReaderWriterLockSlim 读写分离,ConcurrentDictionary 管理多频道
- 配置体系:Microsoft.Extensions.Configuration 双层 JSON(默认层 + 用户层覆盖)
- 状态持久化:CustomXMLParts 内嵌工作簿,ExcelDna.IntelliSense 提供函数与参数提示
- 开发方式:AI 编程类工具搭配国际顶级模型完成
适用场景
- 实时数据看板:订单等业务数据从后端接口实时流入 Excel,按区域、产品线自动汇总刷新
- 生产监控大屏:从 MES 拉取产线数据,按车间、工序展示产量与良率,异常自动标记
- 财务对账监控:对接银行流水按账户、金额区间汇总,异常交易触发重算提醒
- 库存预警:轮询 ERP 库存,低于安全库存的物料自动高亮
- 多系统联动:通过频道隔离在同一工作簿联动订单、仓储、物流等多源数据
原始提交内容(点开查看,可复制全文去问 AI)
wps-udf-live-cache 项目说明
Excel-DNA 自定义函数插件 | 全量快照 + 增量轮询 + 共享缓存 + 下游联动重算
一、项目概述
wps-udf-live-cache 是一个基于 Excel-DNA 的 Excel/WPS 自定义函数插件,核心能力是解决一类经典问题:“先拉全量数据,再定时拉增量变更,多个 Excel 公式共享同一份内存缓存,只有缓存真的变化时依赖它的公式才重算。”
该蓝图引入了 “信号驱动重算” 架构——一个 Formula 负责轮询数据源并推送修订信号,其他公式把信号作为依赖参数传入,由 Excel 的依赖链自动触发重算。数据源支持内建 Demo 模拟模式和 HTTP 真实接口两种模式,可无缝切换。
一句话定位: 让 Excel 拥有实时数据联动能力,无需手动刷新、无需 VBA、无需定时宏。
二、技术栈
| 层级 | 技术选型 | 说明 |
|---|---|---|
| 运行时 | .NET 6(RollForward=LatestPatch) | 兼容 .NET 6+ Desktop Runtime |
| 插件框架 | Excel-DNA 1.9(本地 Patched 版) | 支持 Excel 和 WPS 双宿主 |
| 架构 | x86 / x64 双 xll | 自动适配宿主进程位数 |
| 响应式编程 | System.Reactive(Rx.NET) | BehaviorSubject 实现信号推送 |
| 缓存存储 | DataTable + ReaderWriterLockSlim |
线程安全的内存表,主键索引 |
| HTTP 客户端 | HttpClient(单例共享) |
全量/增量接口调用 |
| 配置管理 | Microsoft.Extensions.Configuration |
appsettings.json + appsettings.user.json 双层配置 |
| 工作簿持久化 | CustomXMLParts |
将缓存状态嵌入工作簿文件 |
| 函数注册 | Excel-DNA Explicit Registration | 显式注册,避免命名冲突 |
| 智能感知 | ExcelDna.IntelliSense | 函数名、参数提示 |
三、核心架构
3.1 信号驱动重算模型
Excel 工作表
A1 = LIVE_CACHE_SIGNAL("orders", 5) 信号源
B1 = LIVE_CACHE_SUM(A1, "orders", "North")
B2 = LIVE_CACHE_QTY(A1, "orders", "South")
B3 = LIVE_CACHE_TABLE(A1, "orders", "", 10)
A1 只负责推送修订信号,不参与业务计算。
下游函数把 signal 作为依赖参数,缓存变化时自动重算。
3.2 数据流架构
全量接口 首次加载 替换内存 DataTable
修订号 +1
增量接口 定时轮询 按主键 upsert/delete
修订号 +1
BehaviorSubject.OnNext() 推送信号
Excel 依赖链自动重算下游公式
3.3 双模式设计
| 模式 | 数据源 | 适用阶段 |
|---|---|---|
| Demo | 内建模拟数据生成器 | 开发调试、功能验证、离线演示 |
| Http | 真实 HTTP API | 生产环境、对接后端业务系统 |
通过修改 appsettings.json 或 appsettings.user.json 中的 Mode 字段即可切换,无需改代码。
3.4 频道隔离
同一插件实例支持多个逻辑频道,不同频道拥有独立的缓存、轮询周期和 HTTP 端点:
频道 "orders" 订单数据缓存,5 秒轮询
频道 "inventory" 库存数据缓存,10 秒轮询
频道 "customers" 客户数据缓存,30 秒轮询
四、核心功能
4.1 缓存信号函数
| 函数 | 功能 | 说明 |
|---|---|---|
LIVE_CACHE_SIGNAL |
启动/复用共享缓存轮询,推送修订信号 | 核心入口,下游公式依赖此信号 |
LIVE_CACHE_SIGNAL_PC |
按调用单元格隔离的信号版本 | 演示 Observe 主题的 caller 标识能力 |
LIVE_CACHE_STATUS |
查看缓存状态 | 修订号、行数、最近同步时间、错误信息 |
4.2 缓存读取函数
| 函数 | 功能 | 说明 |
|---|---|---|
LIVE_CACHE_SUM |
按分组汇总金额 | 支持 groupFilter 筛选 |
LIVE_CACHE_QTY |
按分组汇总数量 | 演示 ExcelParameterConversion 自动类型转换 |
LIVE_CACHE_TABLE |
返回分组汇总表格 | 按金额降序排列,支持 topN 限制 |
4.3 查询句柄函数([ExcelHandle] 模式)
| 函数 | 功能 | 说明 |
|---|---|---|
LIVE_CACHE_QUERY |
创建可复用查询句柄 | 封装 channel + groupFilter |
LIVE_CACHE_QUERY_SUM |
基于句柄的金额汇总 | 多个公式共享同一查询定义 |
LIVE_CACHE_QUERY_TABLE |
基于句柄的表格返回 | 句柄 + signal 联合依赖 |
4.4 配置管理函数
| 函数 | 功能 | 说明 |
|---|---|---|
CFG_GET |
读取配置值 | 演示 .NET 6+ 配置体系入口 |
CFG_RELOAD |
热重载配置 | 无需重启插件即可切换 Demo/Http 模式 |
4.5 工作簿状态函数
| 函数 | 功能 | 说明 |
|---|---|---|
WORKBOOK_STATE_JSON |
读取工作簿中保存的插件状态 | 演示 CustomXMLParts 持久化 |
4.6 Ribbon 命令
| 命令 | 功能 |
|---|---|
保存默认频道缓存状态到工作簿 |
将当前缓存状态写入工作簿的 CustomXMLParts |
清空当前工作簿状态 |
清除工作簿中的插件状态数据 |
五、核心源码结构
src/TestWpsUdfLiveCache/
AddIn.cs # 插件生命周期、日志、运行时装配
AdvancedFeatures.cs # 核心业务逻辑(全部 UDF 函数 + 缓存服务 + 配置 + 状态持久化)
ExcelWorkbookDataOps.cs # Excel COM 互操作封装
HostInteractionGuard.cs # 宿主忙碌检测与保护
WpsBlankWorkbookCleaner.cs # WPS 空白工作簿清理
Properties/AssemblyInfo.cs # 程序集信息
appsettings.json # 默认配置(版本控制提交)
appsettings.user.json # 用户私有配置(不提交版本控制)
TestWpsUdfLiveCache-AddIn.dna # x86 配置
TestWpsUdfLiveCache-AddIn64.dna # x64 配置
关键内部类:
| 类 | 职责 |
|---|---|
DemoLiveDataCacheService |
单例缓存服务,管理多频道轮询、DataTable 读写、信号发布 |
LiveDataChannelState |
单个频道的完整状态:DataTable、轮询循环、修订号、信号主题 |
DemoLiveDataOptions |
配置模型,映射 appsettings.json 的 DemoLiveData 节 |
AppSettingsProvider |
配置加载器,appsettings.json + appsettings.user.json 双层覆盖 |
WorkbookStateStore |
通过 CustomXMLParts 实现缓存状态的工作簿级持久化 |
TimedFunctionHandler |
函数执行时间统计([TimedFunction] 特性) |
六、使用场景
6.1 实时数据看板
- 订单数据从后端接口实时流入 Excel
- 按区域、按产品线自动汇总
- 数据变化时看板自动刷新,无需手动 F5
6.2 生产监控大屏
- 从 MES 系统拉取产线实时数据
- 按车间、按工序分组展示产量和良率
- 异常数据自动标记,管理人员第一时间发现
6.3 财务对账监控
- 对接银行接口,实时拉取交易流水
- 按账户、按金额区间分组汇总
- 发现异常交易时自动触发重算提醒
6.4 库存预警
- 从 ERP 系统轮询库存数据
- 按仓库、按物料类别分组展示
- 低于安全库存的物料自动高亮
6.5 多数据源联动
通过不同频道隔离不同数据源,在同一工作簿中实现多系统数据的实时联动:
频道 "orders" 对接订单系统
频道 "inventory" 对接仓储系统
频道 "delivery" 对接物流系统
七、推荐公式布局
# A1:信号源(5 秒轮询)
=TESTWPSUDFLIVECACHE_LIVE_CACHE_SIGNAL("orders", 5)
# A2:缓存状态查看
=TESTWPSUDFLIVECACHE_LIVE_CACHE_STATUS("orders")
# B5:按区域汇总金额
=TESTWPSUDFLIVECACHE_LIVE_CACHE_SUM($A$1, "orders", "North")
# B6:按区域汇总数量
=TESTWPSUDFLIVECACHE_LIVE_CACHE_QTY($A$1, "orders", "South")
# B8:分组汇总表格
=TESTWPSUDFLIVECACHE_LIVE_CACHE_TABLE($A$1, "orders", "", 20)
关键设计原则:
A1只负责提供修订信号,不参与业务计算- 下游函数把
signal作为第一个参数传入($A$1),建立依赖链 - 信号单元格必须使用绝对引用(
$A$1),否则下拉填充会断开依赖
八、HTTP 接入指南
8.1 从 Demo 切换到 Http
- 先用 Demo 模式跑通缓存联动,验证公式布局正确
- 修改
appsettings.user.json(建议不改appsettings.json,用 user 层覆盖):
{
"DemoLiveData": {
"Mode": "Http",
"FullSnapshotUrl": "https://api.example.com/orders/full",
"DeltaSnapshotUrl": "https://api.example.com/orders/delta",
"AuthHeaderName": "Authorization",
"AuthHeaderValue": "Bearer <token>"
}
}
- 在 Excel 中执行
=CFG_RELOAD()热重载配置 - 观察
LIVE_CACHE_STATUS确认数据已从 HTTP 接口加载
8.2 接口响应规范
全量接口:
{
"data": {
"rows": [
{
"id": "ORD-001",
"group": "North",
"amount": 128.5,
"quantity": 4,
"updatedAtUtc": "2026-07-04T08:00:00Z"
}
]
}
}
增量接口:
{
"data": {
"rows": [
{
"id": "ORD-001",
"group": "North",
"amount": 132.0,
"quantity": 5,
"updatedAtUtc": "2026-07-04T08:05:00Z"
},
{
"id": "ORD-099",
"group": "West",
"amount": 52.3,
"quantity": 1,
"updatedAtUtc": "2026-07-04T08:05:10Z"
}
]
}
}
8.3 关键配置字段
| 字段 | 说明 |
|---|---|
FullRowsJsonPath |
全量响应中数据数组的 JSON 路径(如 data.rows) |
DeltaRowsJsonPath |
增量响应中数据数组的 JSON 路径 |
PrimaryKeyFieldName |
主键字段名,决定缓存按哪一列做 upsert/delete |
UpdatedAtFieldName |
更新时间字段,增量数据比现有记录更旧时会被忽略 |
DeltaSinceParameterName |
增量接口的时间戳查询参数名(如 sinceUtc) |
DeltaLookbackMinutes |
首次增量请求的回溯分钟数 |
DeleteFlagFieldName |
删除标记字段,命中后从缓存中移除该行 |
ChannelParameterName |
频道参数名,用于在 URL 中区分不同频道 |
AuthHeaderName/Value |
HTTP 鉴权头(Bearer Token 等) |
8.4 POST 请求支持
如果接口要求 POST 方法发送 JSON Body:
{
"DemoLiveData": {
"DeltaSnapshotMethod": "POST",
"DeltaRequestBodyTemplate": "{\"channel\":\"{channel}\",\"sinceUtc\":\"{sinceUtc}\"}"
}
}
占位符 {channel} 和 {sinceUtc} 会在请求时自动替换为实际值。
九、功能特色
9.1 信号驱动重算——精确联动
- 不是“定时刷新全部公式”,而是“缓存变化时只重算依赖它的公式”
- 使用
BehaviorSubject作为信号源,下游通过 Excel 的依赖链自动触发 - 减少不必要的计算,提升大工作簿性能
9.2 共享缓存——避免重复请求
- 同一频道的所有公式共享同一份内存
DataTable - 不是每个单元格各自发 HTTP 请求,而是由一个轮询任务统一管理
- 多个下游函数从同一份缓存读取,零额外网络开销
9.3 全量 + 增量同步——高效数据更新
- 首次加载:全量拉取整表数据
- 后续轮询:只拉最近几分钟的增量变更
- 按主键 upsert:存在则更新,不存在则插入
- 按时间戳去重:增量数据比现有记录更旧时自动忽略
- 支持删除语义:通过
DeleteFlagFieldName标记删除
9.4 线程安全设计
ReaderWriterLockSlim保证读写分离- 汇总函数使用读锁,允许多个公式并发读取
- 数据更新使用写锁,保证原子性
BehaviorSubject是线程安全的,信号发布无竞态
9.5 零代码切换 Demo/Http
- 配置驱动,修改 JSON 即可切换数据源
- Demo 模式内置模拟数据生成器,无需外部依赖即可演示
- 支持运行时热重载配置(
CFG_RELOAD)
9.6 配置双层覆盖
appsettings.json:默认配置,可提交版本控制appsettings.user.json:用户私有配置,不提交版本控制- 后者覆盖前者,灵活管理不同环境的配置差异
9.7 工作簿状态持久化
- 通过 Excel 的
CustomXMLParts将缓存状态写入工作簿文件 - 关闭工作簿后重新打开,可查看上次缓存的快照状态
- 适合审计追溯和离线分析
9.8 函数执行计时
[TimedFunction]特性自动记录函数执行耗时- 写入
addin.log,便于性能分析和问题排查
十、面向组合:与 TreeCollections 蓝图的联动
wps-udf-live-cache 和 wps-udf-tree-collections 可以组合使用,构成完整的 BI 分析方案:
wps-udf-live-cache wps-udf-tree-collections
实时数据轮询 维度树构建
共享内存缓存 层级查询
信号驱动重算 作用域汇总
事实聚合
全功能实时 BI 分析插件
例如:从后端接口实时拉取各子公司的收入数据,结合组织架构树做层级汇总,数据变化时报表自动刷新。
十一、与其他蓝图的对比
| 蓝图 | 核心能力 | 适用场景 |
|---|---|---|
wps-udf-only |
纯自定义函数,无共享缓存 | 普通查询函数,不需要联动重算 |
wps-udf-live-cache |
共享缓存 + 信号重算 + 轮询 | 实时数据看板、多函数共享缓存 |
wps-udf-tree-collections |
父子维度树 + BI 层级汇总 | 组织架构、科目树、成本中心分析 |
wps-ribbon-ctp-webview |
Ribbon 界面 + 任务窗格 | 需要交互式 UI 的插件 |
十二、技术要点总结
- 信号驱动重算:
BehaviorSubject+ExcelAsyncUtil.Observe实现精确的缓存变化通知 - 单例缓存服务:
Lazy<T>确保全局唯一实例,ConcurrentDictionary管理多频道隔离 - 全量 + 增量:先
ReplaceAllRows再ApplyDeltaRows,按主键 + 时间戳做 upsert - 线程安全:
ReaderWriterLockSlim读写分离,DataTable主键索引 - 配置热重载:
Microsoft.Extensions.Configuration+ 双层 JSON 文件 - 参数转换:
ExcelParameterConversion将文本自动转换为强类型筛选器 - 执行计时:
FunctionExecutionHandler自定义特性,透明记录函数耗时 - 工作簿持久化:
CustomXMLParts实现状态数据内嵌在工作簿文件中 - HTTP 灵活配置:支持 GET/POST、JSON Path 解析、URL 参数模板、占位符替换
- 双宿主兼容:
ExcelDnaUtil.IsET自动检测 Excel/WPS,统一代码路径
十三、系统要求
- 操作系统:Windows 7 SP1 及以上
- .NET 运行时:.NET 6 Desktop Runtime(x86 或 x64)
- Office 版本:Microsoft Excel 2010+ 或 WPS 2019+
- 位数:x86 或 x64,与 Office/WPS 位数一致
- 网络:Http 模式需要能访问目标 API 端点
十四、最小验证步骤
- 安装插件后打开 Excel/WPS
- 在 A1 输入:
=TESTWPSUDFLIVECACHE_LIVE_CACHE_SIGNAL("orders", 5) - 在 A2 输入:
=TESTWPSUDFLIVECACHE_LIVE_CACHE_STATUS("orders") - 在 B1 输入:
=TESTWPSUDFLIVECACHE_LIVE_CACHE_SUM($A$1, "orders", "North") - 观察 A2 显示缓存状态,B1 显示汇总金额
- 等待几秒后,观察修订号递增,汇总金额自动变化
- 验证通过后,切入 Http 模式对接真实接口