AxisViewModel.cs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. using System;
  2. using System.ComponentModel;
  3. using System.Threading.Tasks;
  4. using Prism.Commands;
  5. using Prism.Mvvm;
  6. using TeamAAS_VP.Interfaces;
  7. using TeamAAS_VP.Models;
  8. namespace TeamAAS_VP.Core.Robots
  9. {
  10. /// <summary>
  11. /// Axis view-model for binding to View: provides Axis + / - commands, axis name and current position.
  12. /// </summary>
  13. public class AxisViewModel : BindableBase, IDisposable
  14. {
  15. private readonly IRobot _robot;
  16. private readonly string _axisName;
  17. private double _currentPosition;
  18. private double _step;
  19. public DelegateCommand AxisPlusCommand { get; private set; }
  20. public DelegateCommand AxisMinusCommand { get; private set; }
  21. /// <summary>
  22. /// 轴名称(X/Y/Z/U)
  23. /// </summary>
  24. public string AxisName => _axisName;
  25. /// <summary>
  26. /// 当前轴位置(从 Robot 读取或命令后更新)
  27. /// </summary>
  28. public double CurrentPosition
  29. {
  30. get => _currentPosition;
  31. private set => SetProperty(ref _currentPosition, value);
  32. }
  33. /// <summary>
  34. /// 每次 jog 的步长(可设置)
  35. /// </summary>
  36. public double Step
  37. {
  38. get => _step;
  39. set
  40. {
  41. if (SetProperty(ref _step, value))
  42. {
  43. RaiseCanExecuteChanged();
  44. }
  45. }
  46. }
  47. public AxisViewModel(string axisName, IRobot robot, double step = 1.0)
  48. {
  49. if (string.IsNullOrWhiteSpace(axisName)) throw new ArgumentNullException(nameof(axisName));
  50. _axisName = axisName.ToUpper();
  51. _robot = robot ?? throw new ArgumentNullException(nameof(robot));
  52. _step = step;
  53. AxisPlusCommand = DelegateCommand.FromAsyncHandler(ExecutePlusAsync, CanExecuteCommands);
  54. AxisMinusCommand = DelegateCommand.FromAsyncHandler(ExecuteMinusAsync, CanExecuteCommands);
  55. // 尝试初始化当前位置(异步,不阻塞构造)
  56. Task.Run(async () => await UpdatePositionFromRobotAsync());
  57. // 订阅机器人属性变化以刷新命令可用性
  58. if (_robot is INotifyPropertyChanged npc)
  59. {
  60. npc.PropertyChanged += Robot_PropertyChanged;
  61. }
  62. }
  63. private void Robot_PropertyChanged(object sender, PropertyChangedEventArgs e)
  64. {
  65. // 监听 CanExecute 或 IsConnected 等关键属性名(Robots 中使用 CanExecute 字段)
  66. if (string.Equals(e.PropertyName, nameof(XYZU_Robot.CanExecute), StringComparison.OrdinalIgnoreCase) ||
  67. string.Equals(e.PropertyName, nameof(IRobot.CanExecute), StringComparison.OrdinalIgnoreCase) ||
  68. string.Equals(e.PropertyName, nameof(IRobot.IsConnected), StringComparison.OrdinalIgnoreCase))
  69. {
  70. RaiseCanExecuteChanged();
  71. }
  72. }
  73. private bool CanExecuteCommands()
  74. {
  75. try
  76. {
  77. if (_robot == null) return false;
  78. // 优先使用机器人公开的 CanExecute 属性(若存在),否则回退到 IsConnected
  79. var canExecuteProp = _robot.GetType().GetProperty("CanExecute");
  80. if (canExecuteProp != null && canExecuteProp.PropertyType == typeof(bool))
  81. {
  82. return (bool)canExecuteProp.GetValue(_robot);
  83. }
  84. return _robot.IsConnected;
  85. }
  86. catch
  87. {
  88. return false;
  89. }
  90. }
  91. private void RaiseCanExecuteChanged()
  92. {
  93. AxisPlusCommand.RaiseCanExecuteChanged();
  94. AxisMinusCommand.RaiseCanExecuteChanged();
  95. }
  96. private async Task ExecutePlusAsync()
  97. {
  98. if (!CanExecuteCommands()) return;
  99. try
  100. {
  101. await _robot.JogAsync(_axisName, Step);
  102. }
  103. catch
  104. {
  105. // 忽略错误,视需求可扩展日志或通知
  106. }
  107. await UpdatePositionFromRobotAsync();
  108. }
  109. private async Task ExecuteMinusAsync()
  110. {
  111. if (!CanExecuteCommands()) return;
  112. try
  113. {
  114. await _robot.JogAsync(_axisName, -Step);
  115. }
  116. catch
  117. {
  118. // 忽略错误
  119. }
  120. await UpdatePositionFromRobotAsync();
  121. }
  122. /// <summary>
  123. /// 从 Robot 读取完整位置并更新当前轴的 CurrentPosition
  124. /// </summary>
  125. public async Task UpdatePositionFromRobotAsync()
  126. {
  127. try
  128. {
  129. var pos = await _robot.GetRobotPosAsync();
  130. if (pos == null) return;
  131. switch (_axisName)
  132. {
  133. case "X":
  134. CurrentPosition = pos.X;
  135. break;
  136. case "Y":
  137. CurrentPosition = pos.Y;
  138. break;
  139. case "Z":
  140. CurrentPosition = pos.Z;
  141. break;
  142. case "U":
  143. CurrentPosition = pos.U;
  144. break;
  145. default:
  146. // 未知轴,保持不变
  147. break;
  148. }
  149. }
  150. catch
  151. {
  152. // 忽略读取错误
  153. }
  154. }
  155. public void Dispose()
  156. {
  157. if (_robot is INotifyPropertyChanged npc)
  158. {
  159. npc.PropertyChanged -= Robot_PropertyChanged;
  160. }
  161. }
  162. }
  163. }