UMG 属性绑定那篇的结论很直白:每帧求值是 UI 性能的原罪。社区为此造了各种轮子(订阅接口、事件总线),Epic 在 UE5.4 把官方答案放进了引擎:Runtime 下的 Model-View-ViewModel 插件(Engine/Plugins/Runtime/MVVM)。它不只是省性能的绑定系统,更是一套把 UI 表现层和业务状态分离的架构约定。这篇按"编译产物 → 运行时管线 → 能力边界"拆。
三个角色与一条通知链
MVVM 插件的标准分层:
- Model:业务数据本身,纯 UObject/USTRUCT,不引用任何 UI;
- ViewModel:
UMVVMViewModelBase派生类,持有 Model 的可绑定状态,对外暴露UPROPERTY+FFieldNotificationId; - View:
UUserWidget上加一个UMVVMView组件(或蓝图编辑器里的 MVVM 绑定面板),把 ViewModel 属性映射到控件属性。
核心机制是 FieldNotify。ViewModel 的属性声明带 FieldNotify 标记符,setter 里调 UE::FieldNotification::FFieldMulticastDelegate::BroadcastFieldValueChanged(ThisClass::FFieldId::XXX)。这套机制引擎级(FieldNotification 模块),不依赖 MVVM 插件——ViewModel 只是把它包装成约定。
和普通 UMG 绑定的本质区别在更新方向:绑定面板生成的每条记录(FMVVMViewBlueprintBinding,含绑定源路径、目标控件属性、可选转换函数)编译进 View 类,运行时不轮询,而是订阅 FieldNotify 委托——值真变了才触发一次求值 + 属性写入。每帧求值的 N 次 VM 调用被换成事件驱动的常数次。上一篇的性能账,MVVM 就是标准答案。
运行时管线的四个阶段
UMVVMView::SetViewModel 触发绑定建立,之后一条绑定的工作循环:
- 订阅:View 按编译期固化的源路径解析出 ViewModel 的字段 ID,挂到 FieldNotify 多播委托上;路径含嵌套(
ViewModel.Inventory.Gold这种)时给路径上每一级 UObject 都挂监听,中间对象换引用自动重挂。 - 通知:ViewModel setter 广播字段变更(这一步是 C++ 直调委托,不经蓝图 VM)。
- 求值:广播回调里执行绑定记录——取新值、跑转换函数(可以在 C++ 或蓝图里)、写目标控件属性。只在第 2 步发生时才发生。
- 评估模式:绑定可配
OneTime/OneWay/TwoWay(控件属性改回写 ViewModel,走同一个 FieldNotify 环)。
编译期信息存在 UMVVMBlueprintView(View 类上的蓝图编译产物),运行时 UMVVMView 按它建图。这套设计和 UMG 生成类一个思路:编辑器面板里的连线 = 编译期序列化的绑定表。
解决了什么
性能问题最先兑现:事件驱动取代轮询,HUD 几十条绑定的开销从每帧摊销变成变化时刻的一次性成本。配合 Slate 失效缓存,静态框架部分终于能常驻 Fast Path。
解耦问题是更深的收益。ViewModel 作为表现层状态的显式边界:UI 团队只面对 ViewModel 的字段和命令(UFUNCTION 暴露的"操作"),不碰玩法对象的业务逻辑;玩法侧改数据结构,只要 ViewModel 适配层更新,界面不动。GAS 项目里常见搭配:ASC 属性变更 → ViewModel 订阅 → FieldNotify → UI,这条链每一环都有明确 owner。
TwoWay 绑定 + 转换函数覆盖了大量胶水代码(输入框 ↔ 数值、枚举 ↔ 本地化文本),不用手写一堆 Set 和回调节点。
没解决什么
手写 setter 的纪律成本。FieldNotify 的正确性依赖"所有修改都走 setter 并广播"——直接改字段、绕过 ViewModel 直接改 Model,绑定静默失效。团队约定和 code review 要兜住,插件帮不上忙。
列表/集合场景仍要手工。动态数量的列表项(背包格子、好友列表)还是要用 UListView + UObject 列表项那套,MVVM 插件不提供集合 diff/虚拟化绑定,复杂列表的桥接代码省不掉。
版本成熟度。5.4 首发的功能,5.5 里绑定面板和编辑器体验还在快速迭代;老项目(4.x 升上来)的存量绑定不会自动迁移,引入它意味着一段双轨期。
判断标准很简单:新项目从第一天立"UI 只访问 ViewModel"的规矩,插件价值立刻兑现;老项目先挑一个新 HUD(计分板、活动界面)试点,把订阅链路和 setter 纪律跑顺,再谈存量迁移。