495 lines
18 KiB
Markdown
495 lines
18 KiB
Markdown
# XP.Hardware.MotionControl 运动控制模块设计规划
|
||
|
||
> 文档版本:v1.0
|
||
> 创建日期:2026-04-10
|
||
> 适用项目:XplorePlane 平面CT工业检测系统
|
||
|
||
---
|
||
|
||
## 1. 背景与硬件描述
|
||
|
||
本模块用于控制平面CT系统中的所有运动轴、旋转轴及安全防护门。
|
||
|
||
### 1.1 直线轴(4轴)
|
||
|
||
| 轴标识 | 说明 | 运动方向 |
|
||
|--------|------|----------|
|
||
| 轴1 SourceZ | 射线源Z方向运动 | 上下 |
|
||
| 轴2 DetectorZ | 探测器Z方向运动 | 上下 |
|
||
| 轴3 StageX | 载物台X方向运动 | 前后 |
|
||
| 轴4 StageY | 载物台Y方向运动 | 左右 |
|
||
|
||
### 1.2 旋转轴(3轴)
|
||
|
||
| 轴标识 | 说明 | 特点 |
|
||
|--------|------|------|
|
||
| 旋转轴1 DetectorSwing | 探测器在XZ平面的旋转摆动 | 有限角度,旋转中心在射线源Z方向延长线上 |
|
||
| 旋转轴2 StageRotation | 载物台围绕XY中心的Z方向旋转 | 可选配置 |
|
||
| 旋转轴3 FixtureRotation | 旋转夹具在载物台XY平面上围绕X方向的旋转 | 可选配置 |
|
||
|
||
### 1.3 安全门
|
||
|
||
防护门,具备状态机控制与互锁信号联动。
|
||
|
||
### 1.4 几何关系
|
||
|
||
```
|
||
FOD(焦点到旋转中心距离)= |SourceZ绝对坐标 - 旋转中心绝对Z坐标|
|
||
FDD(焦点到探测器距离) = |SourceZ绝对坐标 - DetectorZ绝对坐标|
|
||
放大倍率 M = FDD / FOD
|
||
```
|
||
|
||
只有确定了射线源、探测器、载物台旋转中心的绝对坐标,才能准确计算 FOD 和 FDD,进而控制放大倍率。
|
||
|
||
---
|
||
|
||
## 2. 目录结构
|
||
|
||
```
|
||
XP.Hardware.MotionControl/
|
||
├── Abstractions/
|
||
│ ├── ILinearAxis.cs # 直线轴策略接口
|
||
│ ├── IRotaryAxis.cs # 旋转轴策略接口
|
||
│ ├── ISafetyDoor.cs # 安全门策略接口
|
||
│ ├── IMotionSystem.cs # 顶层系统管理接口
|
||
│ ├── LinearAxisBase.cs # 直线轴抽象基类
|
||
│ ├── RotaryAxisBase.cs # 旋转轴抽象基类
|
||
│ ├── SafetyDoorBase.cs # 安全门抽象基类
|
||
│ ├── MotionResult.cs # 统一操作结果类型
|
||
│ └── Enums/
|
||
│ ├── AxisStatus.cs # 轴状态枚举
|
||
│ ├── DoorStatus.cs # 门状态枚举
|
||
│ └── AxisId.cs # 轴标识枚举
|
||
├── Implementations/
|
||
│ ├── PlcLinearAxis.cs # 基于PLC的直线轴实现
|
||
│ ├── PlcRotaryAxis.cs # 基于PLC的旋转轴实现
|
||
│ └── PlcSafetyDoor.cs # 基于PLC的安全门实现
|
||
├── Services/
|
||
│ ├── IMotionControlService.cs # 运动控制业务服务接口
|
||
│ ├── MotionControlService.cs # 服务实现(含轮询线程、几何计算)
|
||
│ └── GeometryCalculator.cs # FOD/FDD/放大倍率计算器
|
||
├── Config/
|
||
│ ├── MotionControlConfig.cs # 配置实体(轴范围、原点、PLC信号名)
|
||
│ └── ConfigLoader.cs # 配置加载器
|
||
├── ViewModels/
|
||
│ └── MotionControlViewModel.cs # 操作面板 ViewModel
|
||
├── Views/
|
||
│ └── MotionControlView.xaml # 操作面板 UserControl(宽350)
|
||
├── Module/
|
||
│ └── MotionControlModule.cs # Prism 模块注册
|
||
├── Documents/
|
||
│ └── MotionControl_Design.md # 本文档
|
||
└── Resources/
|
||
├── Resources.resx
|
||
├── Resources.zh-CN.resx
|
||
└── Resources.en-US.resx
|
||
```
|
||
|
||
---
|
||
|
||
## 3. 核心抽象层设计
|
||
|
||
### 3.1 三类硬件抽象继承关系
|
||
|
||
```
|
||
ILinearAxis IRotaryAxis ISafetyDoor
|
||
│ │ │
|
||
LinearAxisBase RotaryAxisBase SafetyDoorBase
|
||
│ │ │
|
||
PlcLinearAxis PlcRotaryAxis PlcSafetyDoor
|
||
```
|
||
|
||
### 3.2 ILinearAxis 接口职责
|
||
|
||
- 位置读取(实际值)
|
||
- 目标位置写入
|
||
- Jog 正向 / Jog 反向(按住运动,松开停止)
|
||
- 回零
|
||
- 停止
|
||
- 限位状态读取(正限位 / 负限位)
|
||
- 轴状态(Idle / Moving / Homing / Error / Alarm)
|
||
|
||
### 3.3 IRotaryAxis 接口职责
|
||
|
||
- 角度读取(实际值)
|
||
- 目标角度写入
|
||
- Jog 正向 / Jog 反向
|
||
- 回零
|
||
- 停止
|
||
- 角度软限位(MinAngle / MaxAngle,来自配置)
|
||
- 轴状态
|
||
|
||
### 3.4 ISafetyDoor 接口职责
|
||
|
||
- 状态机读取(Unknown / Opening / Open / Closing / Closed / Locked / Error)
|
||
- 开门指令
|
||
- 关门指令
|
||
- 互锁信号读取(是否允许开门)
|
||
|
||
### 3.5 IMotionSystem 顶层接口职责
|
||
|
||
- 按 `AxisId` 枚举索引各直线轴(SourceZ、DetectorZ、StageX、StageY)
|
||
- 按 `RotaryAxisId` 枚举索引各旋转轴(DetectorSwing、StageRotation、FixtureRotation)
|
||
- 持有安全门实例
|
||
- 协调运动:开门前联锁检查
|
||
- 几何计算委托给 `GeometryCalculator`
|
||
|
||
---
|
||
|
||
## 4. 服务层设计
|
||
|
||
### 4.1 IMotionControlService
|
||
|
||
封装业务规则,供 ViewModel 调用:
|
||
|
||
- `StartPolling()` / `StopPolling()` — 启停 PLC 数据轮询
|
||
- `MoveToTarget(AxisId, double)` — 移动指定轴到目标位置
|
||
- `MoveAllToTarget(targets)` — 多轴联动移动
|
||
- `StopAll()` — 停止所有轴
|
||
- `HomeAll()` — 全部回零
|
||
- `JogStart(AxisId, direction)` / `JogStop(AxisId)` — Jog 控制
|
||
- `OpenDoor()` / `CloseDoor()` / `StopDoor()` — 门控制(含联锁前置检查)
|
||
- `ApplyGeometry(fod, fdd)` — 根据 FOD/FDD 反算并移动
|
||
- `GetCurrentGeometry()` — 获取当前 FOD/FDD/M
|
||
|
||
### 4.2 GeometryCalculator
|
||
|
||
```csharp
|
||
// 正算:由轴位置计算几何参数
|
||
double CalcFOD(double sourceZAbs, double stageRotCenterZAbs)
|
||
double CalcFDD(double sourceZAbs, double detectorZAbs)
|
||
double CalcMagnification(double fdd, double fod)
|
||
|
||
// 反算:由目标几何参数计算轴目标位置
|
||
(double sourceZTarget, double detectorZTarget) CalcAxisTargets(double targetFOD, double targetFDD)
|
||
|
||
// 边界检查:目标值是否在轴 Min/Max 范围内
|
||
bool ValidateTargets(double sourceZTarget, double detectorZTarget)
|
||
```
|
||
|
||
绝对坐标计算方式:
|
||
|
||
```
|
||
SourceZ绝对坐标 = SourceZ当前位置 + SourceZOrigin(配置)
|
||
DetectorZ绝对坐标 = DetectorZ当前位置 + DetectorZOrigin(配置)
|
||
旋转中心绝对Z坐标 = StageRotationCenterZ(配置,固定值)
|
||
```
|
||
|
||
### 4.3 轮询线程
|
||
|
||
在 `MotionControlService` 内部使用 `System.Threading.Timer`,周期约 100ms,仅在 PLC 已连接时激活。每次轮询通过 `ISignalDataService.GetValueByName()` 读取所有轴的实际位置和状态,更新到 ViewModel 的可绑定属性。
|
||
|
||
---
|
||
|
||
## 5. 与 PLC 模块的依赖关系
|
||
|
||
MotionControl 通过依赖注入获取 `ISignalDataService`(来自 XP.Hardware.PLC),所有读写操作通过信号逻辑名称进行,不直接操作 PLC 地址。信号名称在配置文件中定义。
|
||
|
||
```
|
||
XP.Hardware.MotionControl
|
||
└── 依赖注入 → ISignalDataService(XP.Hardware.PLC)
|
||
└── 读:GetValueByName<float>("MC_SourceZ_Pos")
|
||
└── 写:EnqueueWrite("MC_SourceZ_Target", value)
|
||
```
|
||
|
||
---
|
||
|
||
## 6. 配置文件设计(App.config)
|
||
|
||
```xml
|
||
<MotionControl>
|
||
<!-- 直线轴配置(单位:mm) -->
|
||
<SourceZ Min="0" Max="500" Origin="0"
|
||
PlcSignalRead="MC_SourceZ_Pos" PlcSignalWrite="MC_SourceZ_Target"
|
||
PlcSignalJogPos="MC_SourceZ_JogPos" PlcSignalJogNeg="MC_SourceZ_JogNeg"
|
||
PlcSignalHome="MC_SourceZ_Home" PlcSignalStop="MC_SourceZ_Stop" />
|
||
<DetectorZ Min="0" Max="600" Origin="0"
|
||
PlcSignalRead="MC_DetZ_Pos" PlcSignalWrite="MC_DetZ_Target"
|
||
PlcSignalJogPos="MC_DetZ_JogPos" PlcSignalJogNeg="MC_DetZ_JogNeg"
|
||
PlcSignalHome="MC_DetZ_Home" PlcSignalStop="MC_DetZ_Stop" />
|
||
<StageX Min="-150" Max="150" Origin="0"
|
||
PlcSignalRead="MC_StageX_Pos" PlcSignalWrite="MC_StageX_Target"
|
||
PlcSignalJogPos="MC_StageX_JogPos" PlcSignalJogNeg="MC_StageX_JogNeg"
|
||
PlcSignalHome="MC_StageX_Home" PlcSignalStop="MC_StageX_Stop" />
|
||
<StageY Min="-150" Max="150" Origin="0"
|
||
PlcSignalRead="MC_StageY_Pos" PlcSignalWrite="MC_StageY_Target"
|
||
PlcSignalJogPos="MC_StageY_JogPos" PlcSignalJogNeg="MC_StageY_JogNeg"
|
||
PlcSignalHome="MC_StageY_Home" PlcSignalStop="MC_StageY_Stop" />
|
||
|
||
<!-- 旋转轴配置(单位:度) -->
|
||
<DetectorSwing Min="-45" Max="45" Origin="0" Enabled="true"
|
||
PlcSignalRead="MC_DetSwing_Angle" PlcSignalWrite="MC_DetSwing_Target"
|
||
PlcSignalJogPos="MC_DetSwing_JogPos" PlcSignalJogNeg="MC_DetSwing_JogNeg"
|
||
PlcSignalHome="MC_DetSwing_Home" PlcSignalStop="MC_DetSwing_Stop" />
|
||
<StageRotation Min="-360" Max="360" Origin="0" Enabled="true"
|
||
PlcSignalRead="MC_StageRot_Angle" PlcSignalWrite="MC_StageRot_Target"
|
||
PlcSignalJogPos="MC_StageRot_JogPos" PlcSignalJogNeg="MC_StageRot_JogNeg"
|
||
PlcSignalHome="MC_StageRot_Home" PlcSignalStop="MC_StageRot_Stop" />
|
||
<FixtureRotation Min="-90" Max="90" Origin="0" Enabled="false"
|
||
PlcSignalRead="MC_FixRot_Angle" PlcSignalWrite="MC_FixRot_Target"
|
||
PlcSignalJogPos="MC_FixRot_JogPos" PlcSignalJogNeg="MC_FixRot_JogNeg"
|
||
PlcSignalHome="MC_FixRot_Home" PlcSignalStop="MC_FixRot_Stop" />
|
||
|
||
<!-- 安全门配置 -->
|
||
<SafetyDoor PlcSignalOpen="MC_Door_Open"
|
||
PlcSignalClose="MC_Door_Close"
|
||
PlcSignalStop="MC_Door_Stop"
|
||
PlcSignalStatus="MC_Door_Status"
|
||
PlcSignalInterlock="MC_Door_Interlock" />
|
||
|
||
<!-- 几何原点(绝对坐标 mm,用于 FOD/FDD 计算) -->
|
||
<Geometry SourceZOrigin="0"
|
||
DetectorZOrigin="600"
|
||
StageRotationCenterZ="300" />
|
||
|
||
<!-- 轮询周期(ms) -->
|
||
<PollingInterval>100</PollingInterval>
|
||
|
||
<!-- 运动速度(%,0-100) -->
|
||
<DefaultVelocity>30</DefaultVelocity>
|
||
<JogVelocity>10</JogVelocity>
|
||
</MotionControl>
|
||
```
|
||
|
||
---
|
||
|
||
## 7. ViewModel 设计
|
||
|
||
### 7.1 属性分组
|
||
|
||
```csharp
|
||
// 直线轴(每轴一组实际值 + 目标值)
|
||
double SourceZActual / SourceZTarget
|
||
double DetectorZActual / DetectorZTarget
|
||
double StageXActual / StageXTarget
|
||
double StageYActual / StageYTarget
|
||
|
||
// 旋转轴(每轴一组,可选轴按配置控制 Visibility)
|
||
double DetSwingActual / DetSwingTarget // 附带角度限制提示文本
|
||
double StageRotActual / StageRotTarget
|
||
double FixtureRotActual / FixtureRotTarget
|
||
|
||
// 几何信息(实时计算,只读显示)
|
||
double FOD / FDD / Magnification
|
||
|
||
// 几何反算输入
|
||
double TargetFOD / TargetFDD / TargetMagnification
|
||
|
||
// 安全门
|
||
DoorStatus DoorStatus
|
||
bool IsInterlocked
|
||
|
||
// 状态
|
||
bool IsMoving
|
||
bool IsPlcConnected
|
||
|
||
// 调试模式(默认 false,折叠隐藏调试区域)
|
||
bool IsDebugMode
|
||
```
|
||
|
||
### 7.2 命令列表
|
||
|
||
```csharp
|
||
// 主操作命令
|
||
ICommand MoveCommand // 执行运动到各轴目标位置
|
||
ICommand StopCommand // 停止所有轴
|
||
ICommand HomeCommand // 全部回零
|
||
ICommand OpenDoorCommand
|
||
ICommand CloseDoorCommand
|
||
ICommand StopDoorCommand
|
||
ICommand ApplyGeometryCommand // 根据 FOD/FDD/M 反算并移动
|
||
|
||
// 调试命令(Jog,按住触发,松开停止)
|
||
ICommand JogPlusCommand // 参数:AxisId
|
||
ICommand JogMinusCommand // 参数:AxisId
|
||
ICommand JogStopCommand // 参数:AxisId
|
||
```
|
||
|
||
---
|
||
|
||
## 8. View 布局设计(宽 350px,UserControl)
|
||
|
||
```
|
||
┌─────────────────────────────────────┐ 350px
|
||
│ [安全门状态] ● 已关闭 [互锁: 正常] │
|
||
├─────────────────────────────────────┤
|
||
│ 直线轴 │
|
||
│ 源Z [实际: 123.4mm] [▲目标▼] │
|
||
│ 探Z [实际: 456.7mm] [▲目标▼] │
|
||
│ 台X [实际: 12.3mm] [▲目标▼] │
|
||
│ 台Y [实际: -5.6mm] [▲目标▼] │
|
||
├─────────────────────────────────────┤
|
||
│ 旋转轴 │
|
||
│ 探摆 [实际: 15.0°] [▲目标▼] │
|
||
│ 限制: -45° ~ +45° │
|
||
│ 台转 [实际: 180.0°] [▲目标▼] │
|
||
│ 夹具 [实际: 0.0°] [▲目标▼] │
|
||
├─────────────────────────────────────┤
|
||
│ 几何信息 │
|
||
│ FOD: 150.0mm FDD: 450.0mm M: 3.0│
|
||
│ [目标FOD▲▼] [目标FDD▲▼] [应用] │
|
||
├─────────────────────────────────────┤
|
||
│ [开始运动] [停止运动] [回零] │
|
||
│ [开门] [关门] │
|
||
├─────────────────────────────────────┤
|
||
│ ▼ 调试模式(默认折叠) │
|
||
│ 源Z [+Jog][-Jog] 探Z [+][-] │
|
||
│ 台X [+Jog][-Jog] 台Y [+][-] │
|
||
│ 探摆 [+Jog][-Jog] 台转[+][-] │
|
||
│ 夹具 [+Jog][-Jog] │
|
||
└─────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 9. FOD/FDD 反算逻辑
|
||
|
||
用户输入目标 FOD 和 FDD(或放大倍率 M),系统自动计算各轴目标位置:
|
||
|
||
```
|
||
// 已知:StageRotationCenterZ(旋转中心绝对Z坐标,来自配置,固定值)
|
||
|
||
// 输入 FOD + FDD:
|
||
SourceZ_target = StageRotationCenterZ - FOD
|
||
DetectorZ_target = SourceZ_target + FDD
|
||
|
||
// 输入 FOD + M(M = FDD/FOD):
|
||
FDD = M * FOD
|
||
DetectorZ_target = SourceZ_target + FDD
|
||
|
||
// 边界检查:
|
||
if SourceZ_target < SourceZ.Min || SourceZ_target > SourceZ.Max → 拒绝并提示
|
||
if DetectorZ_target < DetectorZ.Min || DetectorZ_target > DetectorZ.Max → 拒绝并提示
|
||
```
|
||
|
||
---
|
||
|
||
## 10. 关键安全机制
|
||
|
||
参考旧项目 `ControlDoor.openDoor()` 和 `_130kvMove` 的实现经验:
|
||
|
||
| 机制 | 说明 | 对标旧代码 |
|
||
|------|------|-----------|
|
||
| 运动中防重入 | `IsMoving` 标志位,运动中禁止再次触发运动命令 | `fdcRun` 标志位 |
|
||
| 开门联锁检查 | 开门前通过 `IEventAggregator` 检查是否有扫描进行中 | `ControlDoor.openDoor()` 前置逻辑 |
|
||
| 射线源联锁 | 开门前需确认射线源已关闭(暂不实现,预留扩展点,见下方说明) | `zeroXray2Correct()` 等待归零 |
|
||
| 可选轴隐藏 | `StageRotation` 和 `FixtureRotation` 通过配置 `Enabled` 控制 UI 可见性 | 无对应,新增 |
|
||
| Jog 安全 | Jog 操作通过 `MouseDown/Up` 事件控制,松开立即停止 | `radButton3_MouseDown/Up` |
|
||
|
||
---
|
||
|
||
## 11. Prism 模块注册
|
||
|
||
```csharp
|
||
// MotionControlModule.RegisterTypes()
|
||
containerRegistry.RegisterSingleton<MotionControlConfig>(); // 配置(单例)
|
||
containerRegistry.RegisterSingleton<IMotionSystem, PlcMotionSystem>(); // 系统管理(单例)
|
||
containerRegistry.RegisterSingleton<IMotionControlService, MotionControlService>(); // 服务(单例)
|
||
|
||
// MotionControlModule.OnInitialized()
|
||
// 注册多语言资源到 Fallback Chain
|
||
// 启动 PLC 轮询(若 PLC 已连接)
|
||
```
|
||
|
||
---
|
||
---
|
||
|
||
## 12. 关于射线源联锁的扩展说明(暂不实现)
|
||
|
||
### 12.1 什么是事件聚合器(EventAggregator)
|
||
|
||
Prism 的 `IEventAggregator` 是一个**发布/订阅总线**,用于在模块之间传递消息,而不需要两个模块直接互相引用。
|
||
|
||
类比理解:就像一个广播电台,`RaySource` 模块是"电台"(发布者),`MotionControl` 模块是"收音机"(订阅者),两者只通过"频道"(事件类型)通信,彼此不知道对方的存在。
|
||
|
||
```
|
||
XP.Hardware.RaySource XP.Hardware.MotionControl
|
||
│ │
|
||
│ 发布 RaySourceStatusChangedEvent │
|
||
└──────────→ EventAggregator ──────→ 订阅并响应
|
||
```
|
||
|
||
### 12.2 如何订阅(当需要实现时)
|
||
|
||
**第一步:RaySource 模块已有的事件定义**
|
||
|
||
```csharp
|
||
// XP.Hardware.RaySource/Abstractions/Events/RaySourceStatusChangedEvent.cs
|
||
// 该事件已存在,携带射线源当前状态
|
||
public class RaySourceStatusChangedEvent : PubSubEvent<RaySourceStatus> { }
|
||
```
|
||
|
||
**第二步:MotionControlService 中注入并订阅**
|
||
|
||
```csharp
|
||
public class MotionControlService : IMotionControlService
|
||
{
|
||
private readonly IEventAggregator _eventAggregator;
|
||
private bool _isRaySourceOn = false; // 缓存射线源状态
|
||
|
||
public MotionControlService(IEventAggregator eventAggregator, ...)
|
||
{
|
||
_eventAggregator = eventAggregator;
|
||
|
||
// 订阅射线源状态变化事件
|
||
_eventAggregator
|
||
.GetEvent<RaySourceStatusChangedEvent>()
|
||
.Subscribe(OnRaySourceStatusChanged, ThreadOption.BackgroundThread);
|
||
}
|
||
|
||
private void OnRaySourceStatusChanged(RaySourceStatus status)
|
||
{
|
||
// 根据状态判断射线是否开启
|
||
_isRaySourceOn = (status == RaySourceStatus.XRayOn);
|
||
}
|
||
|
||
public async Task OpenDoor()
|
||
{
|
||
// 开门前检查射线源
|
||
if (_isRaySourceOn)
|
||
{
|
||
_logger.Warn("射线源未关闭,禁止开门 | Ray source is on, door open blocked");
|
||
return;
|
||
}
|
||
// ... 继续开门逻辑
|
||
}
|
||
}
|
||
```
|
||
|
||
**第三步:注意事项**
|
||
|
||
- 订阅时选择 `ThreadOption.BackgroundThread`,避免在 UI 线程处理硬件状态
|
||
- 模块卸载时需要取消订阅,防止内存泄漏:`GetEvent<...>().Unsubscribe(OnRaySourceStatusChanged)`
|
||
- 两个模块之间**不需要互相引用**,只需要共同引用定义事件的程序集(或在各自模块内定义相同结构的事件)
|
||
|
||
### 12.3 预留扩展点
|
||
|
||
当需要实现射线源联锁时,只需在 `MotionControlService.OpenDoor()` 方法开头加入上述订阅逻辑即可,不需要修改任何其他代码。
|
||
|
||
---
|
||
|
||
## 13. 事件定义(Prism EventAggregator)
|
||
```
|
||
Abstractions/Events/
|
||
├── AxisStatusChangedEvent.cs # 轴状态变化事件(AxisId + AxisStatus)
|
||
├── DoorStatusChangedEvent.cs # 门状态变化事件(DoorStatus)
|
||
├── GeometryUpdatedEvent.cs # 几何参数更新事件(FOD + FDD + M)
|
||
└── MotionErrorEvent.cs # 运动错误事件(AxisId + 错误信息)
|
||
```
|
||
|
||
---
|
||
|
||
## 13. 实现优先级建议
|
||
|
||
| 优先级 | 内容 |
|
||
|--------|------|
|
||
| P0 | 配置实体、枚举定义、MotionResult |
|
||
| P0 | ILinearAxis / IRotaryAxis / ISafetyDoor 接口 + 抽象基类 |
|
||
| P1 | PlcLinearAxis / PlcRotaryAxis / PlcSafetyDoor 实现 |
|
||
| P1 | GeometryCalculator |
|
||
| P1 | IMotionControlService + MotionControlService(含轮询) |
|
||
| P2 | MotionControlViewModel |
|
||
| P2 | MotionControlView.xaml(宽350 UserControl) |
|
||
| P3 | MotionControlModule 注册 |
|
||
| P3 | 多语言资源文件 |
|