|
|
@@ -16,6 +16,21 @@ public partial class ViewAViewModel : TranslatableViewModelBase
|
|
|
private System.Timers.Timer? _clockTimer;
|
|
|
private bool _disposed;
|
|
|
|
|
|
+ // ═══════════════════════════════════════════════
|
|
|
+ // 动态模式(Profile + 字典驱动 2D/3D 控件)
|
|
|
+ // ═══════════════════════════════════════════════
|
|
|
+
|
|
|
+ /// <summary>当前项目档案(供 2D/3D 控件动态渲染)</summary>
|
|
|
+ public ProjectProfile? Profile => ProjectService.Current;
|
|
|
+
|
|
|
+ /// <summary>模拟量字典 — 键为 "设备名.属性"</summary>
|
|
|
+ [ObservableProperty] private Dictionary<string, float> _analogValues = new();
|
|
|
+ private HashSet<string> _analogKeys = new();
|
|
|
+
|
|
|
+ /// <summary>数字量字典 — 键为 "设备名.属性"</summary>
|
|
|
+ [ObservableProperty] private Dictionary<string, bool> _digitalValues = new();
|
|
|
+ private HashSet<string> _digitalKeys = new();
|
|
|
+
|
|
|
// ═══════════════════════════════════════════════
|
|
|
// 水箱液位
|
|
|
// ═══════════════════════════════════════════════
|
|
|
@@ -340,6 +355,90 @@ public partial class ViewAViewModel : TranslatableViewModelBase
|
|
|
|
|
|
// 报警由 AlarmService 统一检测,通过 AlarmStateChanged 事件更新
|
|
|
UpdateAlarmStateFromService();
|
|
|
+
|
|
|
+ // 同步动态字典(供 2D/3D 控件动态渲染)
|
|
|
+ UpdateDynamicDictionaries(data);
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>将 PlcDataModel 同步到 AnalogValues / DigitalValues 字典</summary>
|
|
|
+ private void UpdateDynamicDictionaries(PlcDataModel data)
|
|
|
+ {
|
|
|
+ var profile = ProjectService.Current;
|
|
|
+ if (profile == null) return;
|
|
|
+
|
|
|
+ var analogChanged = false;
|
|
|
+ var digitalChanged = false;
|
|
|
+
|
|
|
+ // 泵
|
|
|
+ foreach (var pump in profile.Pumps)
|
|
|
+ {
|
|
|
+ SetAnalog($"{pump.Name}.Current", data.GetAnalogRegister($"{pump.Name}.Current"), ref analogChanged);
|
|
|
+ SetDigital($"{pump.Name}.Run", data.GetDigitalRegister($"{pump.Name}.Run"), ref digitalChanged);
|
|
|
+ SetDigital($"{pump.Name}.Fault", data.GetDigitalRegister($"{pump.Name}.Fault"), ref digitalChanged);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 水箱
|
|
|
+ foreach (var tank in profile.Tanks)
|
|
|
+ {
|
|
|
+ SetAnalog($"{tank.Name}.Level", data.GetAnalogRegister($"{tank.Name}.Level"), ref analogChanged);
|
|
|
+ for (int i = 1; i <= Math.Max(3, profile.Pumps.Count); i++)
|
|
|
+ {
|
|
|
+ var addr = tank.GetStartPumpLevelAddress(i);
|
|
|
+ if (!string.IsNullOrEmpty(addr))
|
|
|
+ SetAnalog($"{tank.Name}.StartPump{i}Level", data.GetAnalogRegister($"{tank.Name}.StartPump{i}Level"), ref analogChanged);
|
|
|
+ }
|
|
|
+ SetAnalog($"{tank.Name}.StopLevel", data.GetAnalogRegister($"{tank.Name}.StopLevel"), ref analogChanged);
|
|
|
+ SetAnalog($"{tank.Name}.ProtectionLevel", data.GetAnalogRegister($"{tank.Name}.ProtectionLevel"), ref analogChanged);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 仪表
|
|
|
+ foreach (var gauge in profile.Gauges)
|
|
|
+ SetAnalog($"{gauge.Name}.Value", data.GetAnalogRegister($"{gauge.Name}.Value"), ref analogChanged);
|
|
|
+
|
|
|
+ // 传感器
|
|
|
+ foreach (var sensor in profile.Sensors)
|
|
|
+ SetAnalog($"{sensor.Name}.Value", data.GetAnalogRegister($"{sensor.Name}.Value"), ref analogChanged);
|
|
|
+
|
|
|
+ // 数字量输入
|
|
|
+ foreach (var di in profile.DigitalInputs)
|
|
|
+ SetDigital($"DI.{di.Name}", data.GetDigitalRegister($"DI.{di.Name}"), ref digitalChanged);
|
|
|
+
|
|
|
+ // 数字量输出
|
|
|
+ foreach (var do_ in profile.DigitalOutputs)
|
|
|
+ SetDigital($"DO.{do_.Name}", data.GetDigitalRegister($"DO.{do_.Name}"), ref digitalChanged);
|
|
|
+
|
|
|
+ // 报警
|
|
|
+ SetDigital("Alarm.Active", AlarmService.Instance.HasActiveAlarm, ref digitalChanged);
|
|
|
+
|
|
|
+ // 重建字典(仅在键集合变化时)
|
|
|
+ if (analogChanged && _analogValues.Count != _analogKeys.Count)
|
|
|
+ {
|
|
|
+ _analogKeys = new HashSet<string>(_analogValues.Keys);
|
|
|
+ AnalogValues = new Dictionary<string, float>(_analogValues);
|
|
|
+ }
|
|
|
+ if (digitalChanged && _digitalValues.Count != _digitalKeys.Count)
|
|
|
+ {
|
|
|
+ _digitalKeys = new HashSet<string>(_digitalValues.Keys);
|
|
|
+ DigitalValues = new Dictionary<string, bool>(_digitalValues);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void SetAnalog(string key, float value, ref bool changed)
|
|
|
+ {
|
|
|
+ if (!_analogValues.TryGetValue(key, out var old) || Math.Abs(old - value) > 0.001f)
|
|
|
+ {
|
|
|
+ _analogValues[key] = value;
|
|
|
+ changed = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void SetDigital(string key, bool value, ref bool changed)
|
|
|
+ {
|
|
|
+ if (!_digitalValues.TryGetValue(key, out var old) || old != value)
|
|
|
+ {
|
|
|
+ _digitalValues[key] = value;
|
|
|
+ changed = true;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/// <summary>
|