ATMArmRobotTwo.xaml.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. using Aitex.Core.Common;
  2. using Aitex.Core.UI.MVVM;
  3. using FurnaceUI.Controls.Common;
  4. //using FurnaceUI.Views.Maintenances;
  5. using MECF.Framework.Common.Equipment;
  6. using Caliburn.Micro;
  7. using Caliburn.Micro.Core;
  8. using System;
  9. using System.Collections.Generic;
  10. using System.ComponentModel;
  11. using System.Linq;
  12. using System.Text;
  13. using System.Threading;
  14. using System.Threading.Tasks;
  15. using System.Windows;
  16. using System.Windows.Controls;
  17. using System.Windows.Data;
  18. using System.Windows.Documents;
  19. using System.Windows.Input;
  20. using System.Windows.Media;
  21. using System.Windows.Media.Animation;
  22. using System.Windows.Media.Imaging;
  23. using System.Windows.Navigation;
  24. using System.Windows.Shapes;
  25. using CB = MECF.Framework.UI.Client.ClientBase;
  26. using MECF.Framework.Common.CommonData;
  27. using FurnaceUI.Views.Maintenances;
  28. namespace FurnaceUI.Controls.Parts
  29. {
  30. /// <summary>
  31. /// ATMDualArmRobot.xaml 的交互逻辑
  32. /// </summary>
  33. public partial class ATMArmRobotTwo : UserControl, INotifyPropertyChanged
  34. {
  35. protected readonly int MoveTime = 300;
  36. private const int AnimationTimeout = 3000; // seconds
  37. public int RotateAngle
  38. {
  39. get { return (int)GetValue(RotateAngleProperty); }
  40. set { SetValue(RotateAngleProperty, value); }
  41. }
  42. // Using a DependencyProperty as the backing store for RotateAngel. This enables animation, styling, binding, etc...
  43. public static readonly DependencyProperty RotateAngleProperty =
  44. DependencyProperty.Register("RotateAngel", typeof(int), typeof(ATMArmRobotTwo), new PropertyMetadata(0));
  45. public ModuleName Station
  46. {
  47. get { return (ModuleName)GetValue(StationProperty); }
  48. set { SetValue(StationProperty, value); }
  49. }
  50. // Using a DependencyProperty as the backing store for Station. This enables animation, styling, binding, etc...
  51. public static readonly DependencyProperty StationProperty =
  52. DependencyProperty.Register("Station", typeof(ModuleName), typeof(ATMArmRobotTwo), new PropertyMetadata(ModuleName.Robot));
  53. public ICommand Command
  54. {
  55. get { return (ICommand)GetValue(CommandProperty); }
  56. set { SetValue(CommandProperty, value); }
  57. }
  58. // Using a DependencyProperty as the backing store for Command. This enables animation, styling, binding, etc...
  59. public static readonly DependencyProperty CommandProperty =
  60. DependencyProperty.Register("Command", typeof(ICommand), typeof(ATMArmRobotTwo), new PropertyMetadata(null));
  61. public string RobotTarget
  62. {
  63. get { return (string)GetValue(RobotTargetProperty); }
  64. set { SetValue(RobotTargetProperty, value); }
  65. }
  66. private RobotAction CurrentAction
  67. {
  68. get; set;
  69. }
  70. public string WaferRobotStatus
  71. {
  72. get { return (string)GetValue(WaferRobotStatusProperty); }
  73. set { SetValue(WaferRobotStatusProperty, value); }
  74. }
  75. // Using a DependencyProperty as the backing store for WaferRobotStatus. This enables animation, styling, binding, etc...
  76. public static readonly DependencyProperty WaferRobotStatusProperty =
  77. DependencyProperty.Register("WaferRobotStatus", typeof(string), typeof(ATMArmRobotTwo), new PropertyMetadata(null, WaferRobotStatusChangedCallback));
  78. static void WaferRobotStatusChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
  79. {
  80. var self = (ATMArmRobotTwo)d;
  81. var test = d;
  82. switch ((string)e.NewValue)
  83. {
  84. case "Homing":
  85. self.RootImagePath = "/FurnaceUI;component/Resources/Images/Controls3/hgz1y.png";
  86. self.Canvas1ImagePath = "/FurnaceUI;component/Resources/Images/Controls3/rb1y.png";
  87. self.Canvas2ImagePath = "/FurnaceUI;component/Resources/Images/Controls3/rb1y.png";
  88. self.Canvas3ImagePath = "/FurnaceUI;component/Resources/Images/Controls3/rb3y.png";
  89. break;
  90. case "Idle":
  91. case "InTransfer":
  92. case "Picking":
  93. case "Placing":
  94. self.RootImagePath = "/FurnaceUI;component/Resources/Images/Controls3/hgz1g.png";
  95. self.Canvas1ImagePath = "/FurnaceUI;component/Resources/Images/Controls3/rb1g.png";
  96. self.Canvas2ImagePath = "/FurnaceUI;component/Resources/Images/Controls3/rb1g.png";
  97. self.Canvas3ImagePath = "/FurnaceUI;component/Resources/Images/Controls3/rb3g.png";
  98. break;
  99. case "Error":
  100. self.RootImagePath = "/FurnaceUI;component/Resources/Images/Controls3/hgz1r.png";
  101. self.Canvas1ImagePath = "/FurnaceUI;component/Resources/Images/Controls3/rb1r.png";
  102. self.Canvas2ImagePath = "/FurnaceUI;component/Resources/Images/Controls3/rb1r.png";
  103. self.Canvas3ImagePath = "/FurnaceUI;component/Resources/Images/Controls3/rb3r.png";
  104. break;
  105. default:
  106. break;
  107. }
  108. }
  109. public string RootImagePath
  110. {
  111. get { return (string)GetValue(RootImagePathProperty); }
  112. set { SetValue(RootImagePathProperty, value); }
  113. }
  114. // Using a DependencyProperty as the backing store for RootImagePath. This enables animation, styling, binding, etc...
  115. public static readonly DependencyProperty RootImagePathProperty =
  116. DependencyProperty.Register("RootImagePath", typeof(string), typeof(ATMArmRobotTwo), new FrameworkPropertyMetadata("/FurnaceUI;component/Resources/Images/Controls3/hgz1y.png", FrameworkPropertyMetadataOptions.AffectsRender));
  117. public string Canvas1ImagePath
  118. {
  119. get { return (string)GetValue(Canvas1ImagePathProperty); }
  120. set { SetValue(Canvas1ImagePathProperty, value); }
  121. }
  122. // Using a DependencyProperty as the backing store for RootImagePath. This enables animation, styling, binding, etc...
  123. public static readonly DependencyProperty Canvas1ImagePathProperty =
  124. DependencyProperty.Register("Canvas1ImagePath", typeof(string), typeof(ATMArmRobotTwo), new FrameworkPropertyMetadata("/FurnaceUI;component/Resources/Images/Controls3/rb1y.png", FrameworkPropertyMetadataOptions.AffectsRender));
  125. public string Canvas2ImagePath
  126. {
  127. get { return (string)GetValue(Canvas2ImagePathProperty); }
  128. set { SetValue(Canvas2ImagePathProperty, value); }
  129. }
  130. // Using a DependencyProperty as the backing store for RootImagePath. This enables animation, styling, binding, etc...
  131. public static readonly DependencyProperty Canvas2ImagePathProperty =
  132. DependencyProperty.Register("Canvas2ImagePath", typeof(string), typeof(ATMArmRobotTwo), new FrameworkPropertyMetadata("/FurnaceUI;component/Resources/Images/Controls3/rb1y.png", FrameworkPropertyMetadataOptions.AffectsRender));
  133. public string Canvas3ImagePath
  134. {
  135. get { return (string)GetValue(Canvas3ImagePathProperty); }
  136. set { SetValue(Canvas3ImagePathProperty, value); }
  137. }
  138. // Using a DependencyProperty as the backing store for RootImagePath. This enables animation, styling, binding, etc...
  139. public static readonly DependencyProperty Canvas3ImagePathProperty =
  140. DependencyProperty.Register("Canvas3ImagePath", typeof(string), typeof(ATMArmRobotTwo), new FrameworkPropertyMetadata("/FurnaceUI;component/Resources/Images/Controls3/rb3y.png", FrameworkPropertyMetadataOptions.AffectsRender));
  141. public static readonly DependencyProperty RobotTargetProperty =
  142. DependencyProperty.Register("RobotTarget", typeof(string), typeof(ATMArmRobotTwo), new FrameworkPropertyMetadata(ModuleName.Robot.ToString(), FrameworkPropertyMetadataOptions.AffectsRender));
  143. public Dictionary<string, StationPosition> StationPosition
  144. {
  145. get { return (Dictionary<string, StationPosition>)GetValue(StationPositionProperty); }
  146. set { SetValue(StationPositionProperty, value); }
  147. }
  148. // Using a DependencyProperty as the backing store for StationPosition. This enables animation, styling, binding, etc...
  149. public static readonly DependencyProperty StationPositionProperty =
  150. DependencyProperty.Register("StationPosition", typeof(Dictionary<string, StationPosition>), typeof(ATMArmRobotTwo), new PropertyMetadata(null, PropertyChangedCallback));
  151. public string ArmAExtended
  152. {
  153. get { return (string)GetValue(ArmAExtendedProperty); }
  154. set { SetValue(ArmAExtendedProperty, value); }
  155. }
  156. // Using a DependencyProperty as the backing store for ArmAExtended. This enables animation, styling, binding, etc...
  157. public static readonly DependencyProperty ArmAExtendedProperty =
  158. DependencyProperty.Register("ArmAExtended", typeof(string), typeof(ATMArmRobotTwo), new FrameworkPropertyMetadata(RobotConstant.RobotRetract, FrameworkPropertyMetadataOptions.AffectsRender));
  159. public string ArmBExtended
  160. {
  161. get { return (string)GetValue(ArmBExtendedProperty); }
  162. set { SetValue(ArmBExtendedProperty, value); }
  163. }
  164. // Using a DependencyProperty as the backing store for armBExtended. This enables animation, styling, binding, etc...
  165. public static readonly DependencyProperty ArmBExtendedProperty =
  166. DependencyProperty.Register("ArmBExtended", typeof(string), typeof(ATMArmRobotTwo), new FrameworkPropertyMetadata(RobotConstant.RobotRetract, FrameworkPropertyMetadataOptions.AffectsRender));
  167. public WaferInfo[] RobotWafers
  168. {
  169. get { return (WaferInfo[])GetValue(RobotWafersProperty); }
  170. set { SetValue(RobotWafersProperty, value); }
  171. }
  172. // Using a DependencyProperty as the backing store for RobotWafers. This enables animation, styling, binding, etc...
  173. public static readonly DependencyProperty RobotWafersProperty =
  174. DependencyProperty.Register("RobotWafers", typeof(WaferInfo[]), typeof(ATMArmRobotTwo), new PropertyMetadata(null, PropertyChangedCallback));
  175. public CB.WaferInfo Wafer1
  176. {
  177. get { return (CB.WaferInfo)GetValue(Wafer1Property); }
  178. set { SetValue(Wafer1Property, value);
  179. }
  180. }
  181. // Using a DependencyProperty as the backing store for Wafer1. This enables animation, styling, binding, etc...
  182. public static readonly DependencyProperty Wafer1Property =
  183. DependencyProperty.Register("Wafer1", typeof(CB.WaferInfo), typeof(ATMArmRobotTwo), new PropertyMetadata(null));
  184. public CB.WaferInfo Wafer2
  185. {
  186. get { return (CB.WaferInfo)GetValue(Wafer2Property); }
  187. set { SetValue(Wafer2Property, value); }
  188. }
  189. // Using a DependencyProperty as the backing store for Wafer2. This enables animation, styling, binding, etc...
  190. public static readonly DependencyProperty Wafer2Property =
  191. DependencyProperty.Register("Wafer2", typeof(CB.WaferInfo), typeof(ATMArmRobotTwo), new PropertyMetadata(null));
  192. public CB.WaferInfo Wafer3
  193. {
  194. get { return (CB.WaferInfo)GetValue(Wafer3Property); }
  195. set { SetValue(Wafer3Property, value); }
  196. }
  197. // Using a DependencyProperty as the backing store for Wafer3. This enables animation, styling, binding, etc...
  198. public static readonly DependencyProperty Wafer3Property =
  199. DependencyProperty.Register("Wafer3", typeof(CB.WaferInfo), typeof(ATMArmRobotTwo), new PropertyMetadata(null));
  200. public CB.WaferInfo Wafer4
  201. {
  202. get { return (CB.WaferInfo)GetValue(Wafer4Property); }
  203. set { SetValue(Wafer4Property, value); }
  204. }
  205. // Using a DependencyProperty as the backing store for Wafer2. This enables animation, styling, binding, etc...
  206. public static readonly DependencyProperty Wafer4Property =
  207. DependencyProperty.Register("Wafer4", typeof(CB.WaferInfo), typeof(ATMArmRobotTwo), new PropertyMetadata(null));
  208. public CB.WaferInfo Wafer5
  209. {
  210. get { return (CB.WaferInfo)GetValue(Wafer5Property); }
  211. set { SetValue(Wafer5Property, value); }
  212. }
  213. // Using a DependencyProperty as the backing store for Wafer2. This enables animation, styling, binding, etc...
  214. public static readonly DependencyProperty Wafer5Property =
  215. DependencyProperty.Register("Wafer5", typeof(CB.WaferInfo), typeof(ATMArmRobotTwo), new PropertyMetadata(null));
  216. public RobotMoveInfo RobotMoveInfo
  217. {
  218. get { return (RobotMoveInfo)GetValue(RobotMoveInfoProperty); }
  219. set { SetValue(RobotMoveInfoProperty, value); }
  220. }
  221. public static readonly DependencyProperty RobotMoveInfoProperty =
  222. DependencyProperty.Register("RobotMoveInfo", typeof(RobotMoveInfo), typeof(ATMArmRobotTwo), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender));
  223. private string CurrentPosition;
  224. private string CurrentArmA;
  225. private string CurrentArmB;
  226. private List<MenuItem> menu;
  227. public List<MenuItem> Menu
  228. {
  229. get
  230. {
  231. return menu;
  232. }
  233. set
  234. {
  235. menu = value;
  236. PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Menu"));
  237. }
  238. }
  239. public ICommand MoveCommand
  240. {
  241. get
  242. {
  243. return new DelegateCommand<object>(MoveTo);
  244. }
  245. }
  246. private AnimationQueue queue;
  247. public event PropertyChangedEventHandler PropertyChanged;
  248. static void PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
  249. {
  250. var self = (ATMArmRobotTwo)d;
  251. switch (e.Property.Name)
  252. {
  253. case "StationPosition":
  254. var positions = (Dictionary<string, StationPosition>)e.NewValue;
  255. //var menu1 = new MenuItem() { Header = "Arm" };
  256. var subMenu1 = positions.Select(x => new MenuItem() { Header = x.Key, Command = self.MoveCommand, CommandParameter = new Tuple<string, string, string>(x.Key, RobotConstant.RobotExtend, RobotConstant.RobotRetract) }).ToList();
  257. //foreach (var menu in subMenu1)
  258. //{
  259. // menu1.Items.Add(menu);
  260. //}
  261. self.menu = subMenu1;// new List<MenuItem>().Add(subMenu1);
  262. break;
  263. case "RobotWafers":
  264. //if (e.NewValue == null)
  265. //{
  266. // self.Wafer1 = null;
  267. // self.Wafer2 = null;
  268. //}
  269. //else
  270. //{
  271. // if (self.RobotWafers.Length > 1)
  272. // {
  273. // self.Wafer1 = self.RobotWafers[0];
  274. // self.Wafer2 = self.RobotWafers[1];
  275. // }
  276. //}
  277. break;
  278. default:
  279. break;
  280. }
  281. }
  282. public ATMArmRobotTwo()
  283. {
  284. #if DEBUG
  285. System.Diagnostics.PresentationTraceSources.DataBindingSource.Switch.Level = System.Diagnostics.SourceLevels.Critical;
  286. #endif
  287. InitializeComponent();
  288. root.DataContext = this;
  289. queue = new AnimationQueue("Robot Animation");
  290. queue.StatusUpdated += Queue_StatusUpdated;
  291. canvas1.Rotate(0);
  292. canvas2.Rotate(180);
  293. //canvas3.Rotate(180);
  294. CurrentPosition = ModuleName.System.ToString();
  295. CurrentArmA = CurrentArmB = RobotConstant.RobotRetract;
  296. }
  297. protected override void OnRender(DrawingContext drawingContext)
  298. {
  299. base.OnRender(drawingContext);
  300. if (DesignerProperties.GetIsInDesignMode(this))
  301. {
  302. return;
  303. }
  304. if (RobotMoveInfo != null && RobotMoveInfo.BladeTarget != "Robot")
  305. {
  306. var needMove = CurrentPosition != RobotMoveInfo.BladeTarget;
  307. if (needMove)
  308. {
  309. CurrentAction = RobotMoveInfo.Action;
  310. CurrentPosition = RobotMoveInfo.BladeTarget;
  311. LogMsg($" RobotMoveInfo, action:{RobotMoveInfo.Action} armTarget:{RobotMoveInfo.ArmTarget} bladeTarget:{RobotMoveInfo.BladeTarget}");
  312. Invoke(() => MoveRobot(RobotMoveInfo));
  313. }
  314. }
  315. //if (RobotTarget != null || ArmAExtended != null || ArmBExtended != null)
  316. //{
  317. // LogMsg(string.Format("Received ------ Target: {0} ArmA: {1} ArmB: {2} ", RobotTarget, ArmAExtended, ArmBExtended));
  318. // queue.EnqueueStatus(new AnimationParameter() { Target = RobotTarget, ArmA = ArmAExtended, ArmB = ArmBExtended });
  319. //}
  320. }
  321. private void Queue_StatusUpdated(object sender, StatusUpdateArgs e)
  322. {
  323. LogMsg(string.Format("Target: {0} - {1}", CurrentPosition, e.Parameter.Target));
  324. var nextEvent = new AutoResetEvent(false);
  325. var next = new System.Action(() =>
  326. {
  327. nextEvent.Set();
  328. });
  329. var wait = new System.Action(() =>
  330. {
  331. if (!nextEvent.WaitOne(AnimationTimeout))
  332. {
  333. LogMsg("Aniamtion time out!");
  334. }
  335. });
  336. var done = new System.Action(() =>
  337. {
  338. CurrentPosition = e.Parameter.Target;
  339. CurrentArmA = e.Parameter.ArmA;
  340. CurrentArmB = e.Parameter.ArmB;
  341. e.Event.Set();
  342. });
  343. var needMove = CurrentPosition != e.Parameter.Target || CurrentArmA != e.Parameter.ArmA || CurrentArmB != e.Parameter.ArmB;
  344. if (needMove)
  345. {
  346. Invoke(() => MoveRobot(e.Parameter, next));
  347. wait();
  348. }
  349. done();
  350. }
  351. private void MoveRobot(AnimationParameter parameter, System.Action onComplete = null)
  352. {
  353. MoveToStart(parameter.Target, () => TranslateTo(parameter.Target, () => MoveToEnd(parameter, onComplete)));
  354. }
  355. private void MoveRobot(RobotMoveInfo moveInfo)
  356. {
  357. canvas1.Stop();
  358. canvas2.Stop();
  359. canvas3.Stop();
  360. var target = moveInfo.BladeTarget;
  361. var arm = moveInfo.ArmTarget;
  362. AnimationParameter animationParameter = new AnimationParameter() { ArmA = moveInfo.ArmTarget.ToString(), Target = moveInfo.BladeTarget };
  363. MoveToStart(target, () => TranslateTo(target, () => MoveToEnd(animationParameter, null)));
  364. }
  365. private void MoveToStart(string station, System.Action onComplete = null)
  366. {
  367. if (StationPosition == null)
  368. return;
  369. var position = StationPosition[station];
  370. canvas1.Rotate(position.StartPosition.Root, true, MoveTime);
  371. canvas2.Rotate(position.StartPosition.Arm, true, MoveTime);
  372. canvas3.Rotate(position.StartPosition.Hand, true, MoveTime);
  373. CurrentPosition = station;
  374. onComplete?.Invoke();
  375. }
  376. private void MoveToEnd(AnimationParameter parameter, System.Action onComplete = null)
  377. {
  378. var position = StationPosition[parameter.Target];
  379. //var extended = false;
  380. //if (parameter.ArmA == RobotConstant.RobotExtend)
  381. //{
  382. // extended = true;
  383. canvas1.Rotate(position.EndPosition.Root, true, MoveTime, 0, 0, onComplete);
  384. canvas2.Rotate(position.EndPosition.Arm, true, MoveTime);
  385. canvas3.Rotate(position.EndPosition.Hand, true, MoveTime);
  386. //}
  387. //if (!extended)
  388. //{
  389. onComplete?.Invoke();
  390. //}
  391. CurrentPosition = parameter.Target;
  392. }
  393. private void TranslateTo(string station, System.Action onComplete = null)
  394. {
  395. var position = StationPosition[station];
  396. if (position.StartPosition.X.HasValue)
  397. {
  398. Translate(position.StartPosition.X.Value, onComplete);
  399. }
  400. //else
  401. //{
  402. onComplete?.Invoke();
  403. //}
  404. }
  405. double oldX = 0;
  406. private void Translate(int x, System.Action onComplete = null)
  407. {
  408. //var storyBoard = new Storyboard();
  409. //var oldX = translate.X;
  410. AnimationHelper.TranslateY(root, (int)oldX, x, MoveTime, onComplete);
  411. oldX = translate.X;
  412. //var animation = new DoubleAnimation(oldX, x, TimeSpan.FromMilliseconds(MoveTime));
  413. //storyBoard.Children.Add(animation);
  414. //Storyboard.SetTarget(animation, root);
  415. //var propertyChain = new DependencyProperty[]
  416. // {
  417. // Canvas.RenderTransformProperty,
  418. // TransformGroup.ChildrenProperty,
  419. // TranslateTransform.XProperty
  420. // };
  421. //string thePath = "(0).(1)[1].(2)";
  422. //PropertyPath myPropertyPath = new PropertyPath(thePath, propertyChain);
  423. //Storyboard.SetTargetProperty(animation, myPropertyPath);
  424. //storyBoard.Completed += (s, e) =>
  425. //{
  426. // //InvalidateVisual();
  427. // if (onComplete != null)
  428. // {
  429. // onComplete();
  430. // }
  431. //};
  432. //storyBoard.Begin();
  433. }
  434. private void MoveTo(object obj)
  435. {
  436. var para = (Tuple<string, string, string>)obj;
  437. MoveRobot(new AnimationParameter() { Target = para.Item1, ArmA = para.Item2, ArmB = para.Item3 });
  438. }
  439. private void Invoke(System.Action action)
  440. {
  441. Dispatcher.Invoke(action);
  442. }
  443. private void LogMsg(string msg)
  444. {
  445. var source = "ATMRobot";
  446. Console.WriteLine("{0} {1}", source, msg);
  447. }
  448. private void Viewbox_MouseDown(object sender, MouseButtonEventArgs e)
  449. {
  450. var windowManager = IoC.Get<IWindowManager>();
  451. WaferRobotViewModel waferRobotViewModel = new WaferRobotViewModel();
  452. waferRobotViewModel.SystemName = "SMIFA";
  453. (windowManager as WindowManager)?.ShowDialogWithTitle(waferRobotViewModel, null, "WaferRobot Status");
  454. }
  455. }
  456. }