RecipeGasXmlViewModel.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671
  1. using Aitex.Core.Common.DeviceData;
  2. using Aitex.Core.RT.IOCore;
  3. using Aitex.Core.UI.Control;
  4. using Aitex.Core.UI.ControlDataContext;
  5. using Aitex.Core.UI.DeviceControl;
  6. using Aitex.Core.Util;
  7. using Caliburn.Micro.Core;
  8. using DocumentFormat.OpenXml.Drawing.Charts;
  9. using DocumentFormat.OpenXml.Office2019.Excel.RichData;
  10. using DocumentFormat.OpenXml.Wordprocessing;
  11. using FurnaceUI.Models;
  12. using MECF.Framework.Common;
  13. using MECF.Framework.Common.DataCenter;
  14. using MECF.Framework.Common.Equipment;
  15. using MECF.Framework.Common.OperationCenter;
  16. using MECF.Framework.UI.Client.CenterViews.Editors.Recipe;
  17. using MECF.Framework.UI.Core.Control;
  18. using MECF.Framework.UI.Core.DxfScript;
  19. using MECF.Framework.UI.Core.DxfScript.Converter;
  20. using MECF.Framework.UI.Core.ExtendedControls;
  21. using OpenSEMI.ClientBase;
  22. using SciChart.Core.AttachedProperties;
  23. using System;
  24. using System.Collections.Generic;
  25. using System.Linq;
  26. using System.Text;
  27. using System.Threading.Tasks;
  28. using System.Windows;
  29. using System.Xml.Linq;
  30. using static MECF.Framework.UI.Core.DxfScript.Express;
  31. using static System.Windows.Forms.VisualStyles.VisualStyleElement.Window;
  32. namespace FurnaceUI.Views.Editors
  33. {
  34. public class RecipeGasXmlViewModel : FurnaceUIViewModelBase, IUserFunctions, IDisposable
  35. {
  36. private string _PM = $"{ModuleName.PM1.ToString()}.";
  37. private Dictionary<string, string> ConvertNameDict = new Dictionary<string, string>()
  38. {
  39. };
  40. public List<string> ChangeMfcValue = new List<string>();
  41. public Window WinOwner { get; set; }
  42. private string _selectedStepName;
  43. public string SelectedStepName
  44. {
  45. get
  46. {
  47. return _selectedStepName;
  48. }
  49. set
  50. {
  51. _selectedStepName = value;
  52. NotifyOfPropertyChange("SelectedStepName");
  53. }
  54. }
  55. private Step _step;
  56. public Step SelectedStep
  57. {
  58. get => _step;
  59. set
  60. {
  61. _step = value;
  62. NotifyOfPropertyChange("SelectedStep");
  63. }
  64. }
  65. public delegate void ChangedStepHandler(Step step);
  66. public event ChangedStepHandler ChangedStepEvent;
  67. public RecipeDataBase CurrentRecipe { get; set; }
  68. private GasPanelStateType _selectedGasStateType = GasPanelStateType.Recipe;
  69. public GasPanelStateType SelectedGasStateType
  70. {
  71. get
  72. {
  73. return _selectedGasStateType;
  74. }
  75. set
  76. {
  77. _selectedGasStateType = value;
  78. NotifyOfPropertyChange(nameof(SelectedGasStateType));
  79. }
  80. }
  81. private bool _isUsePREVBtn = false;
  82. public bool IsUsePREVBtn
  83. {
  84. get => _isUsePREVBtn;
  85. set
  86. {
  87. _isUsePREVBtn = value;
  88. NotifyOfPropertyChange("IsUsePREVBtn");
  89. }
  90. }
  91. private bool _isUseNEXTBtn = false;
  92. public bool IsUseNEXTBtn
  93. {
  94. get => _isUseNEXTBtn;
  95. set
  96. {
  97. _isUseNEXTBtn = value;
  98. NotifyOfPropertyChange("IsUseNEXTBtn");
  99. }
  100. }
  101. public RecipeGasXmlViewModel()
  102. {
  103. UserFunctionsEvents.ClearAll();
  104. UserFunctionsEvents.RegisterEvent<Dictionary<string, object>>("SwichValue", SwichValue);
  105. UserFunctionsEvents.RegisterEvent<Dictionary<string, object>>("MfcFlowTouchUp", MfcFlowTouchUp);
  106. UserFunctionsEvents.RegisterEvent<Dictionary<string, object>>("ValveTouchUp", ValveTouchUp);
  107. }
  108. protected override void OnViewLoaded(object view)
  109. {
  110. base.OnViewLoaded(view);
  111. GetIoValveBtn();
  112. SetValveVirtualFeedbackValue();
  113. SwitchKey(false);
  114. SetPREVAndNEXTBtn();
  115. }
  116. /// <summary>
  117. /// DevicePM中有些IoValve命名存在问题,没有表明是btn类型,故需要转化下。
  118. /// </summary>
  119. private void GetIoValveBtn()
  120. {
  121. ConvertNameDict.Clear();
  122. var valueSetsName = SelectedStep.ValveSets.Where(a => a.Name.StartsWith("ValveAV")).Select(a => $"{_PM}{a.Name}Btn").ToList();
  123. var valuveDatas = QueryDataClient.Instance.Service.PollData(valueSetsName);
  124. foreach (var item in valuveDatas)
  125. {
  126. var valveItem = SelectedStep.ValveSets.Where(a => $"{_PM}{a.Name}Btn" == item.Key).FirstOrDefault().Name;
  127. ConvertNameDict.Add(valveItem, item.Value.ToString());
  128. }
  129. }
  130. protected override void InvokeAfterUpdateProperty(Dictionary<string, object> data)
  131. {
  132. base.InvokeAfterUpdateProperty(data);
  133. GasMapProvider.GasMap.ModifyDrag();
  134. }
  135. /// <summary>
  136. /// 切换Key
  137. /// </summary>
  138. /// <param name="isMonitor"></param>
  139. public void SwitchKey(bool isMonitor = true)
  140. {
  141. ScriptVariables.IsFetchRT = isMonitor;
  142. foreach (var item in GasMapProvider.GasMap.Valves)
  143. {
  144. var realKey = $"{ModuleName.PM1.ToString()}.{item.Name}.Feedback";
  145. item.Key = isMonitor ? realKey : $"{realKey.Replace(_PM, "")}";
  146. }
  147. foreach (var item in GasMapProvider.GasMap.Buttons)
  148. {
  149. bool isExextue = item.BoolCondition != null;
  150. var realKey = $"{ModuleName.PM1}.{item.InnerText.Text}Enable";
  151. if (isExextue)
  152. {
  153. item.BoolCondition.Execute();
  154. realKey = item.BoolCondition.ReadBoolValue().Item1;
  155. }
  156. item.DataKey = isMonitor ? realKey : $"{realKey.Replace(_PM, "")}";
  157. }
  158. foreach (var item in GasMapProvider.GasMap.Analogs)
  159. {
  160. item.Brush = GasMapProvider.InitMFCColor;
  161. if (ChangeMfcValue.Contains(item.Name) && !isMonitor)
  162. {
  163. item.Brush = GasMapProvider.ChangeMFCColor;
  164. }
  165. var realKey = $"{ModuleName.PM1}.{item.Name}.Feedback";
  166. item.ValueKey = isMonitor ? realKey : $"{realKey.Replace(_PM, "")}";
  167. }
  168. foreach (var item in GasMapProvider.GasMap.Circles)
  169. {
  170. bool isExextue = item.ClickCondition == null && item.BoolCondition != null && item.StringCondition == null;
  171. if (isExextue)
  172. {
  173. item.BoolCondition.Execute();
  174. item.Key = item.BoolCondition.ReadBoolValue().Item1;
  175. continue;
  176. }
  177. }
  178. }
  179. /// <summary>
  180. /// 初始化虚拟值
  181. /// </summary>
  182. public void SetValveVirtualFeedbackValue()
  183. {
  184. var str = $"{ModuleName.PM1.ToString()}.";
  185. ChangeMfcValue.Clear();
  186. Dictionary<string, object> btnNameKeyValues = new Dictionary<string, object>();
  187. foreach (var item in SelectedStep.ValveSets)
  188. {
  189. var itemName = item.Name;
  190. if (ConvertNameDict.ContainsKey(item.Name))
  191. {
  192. itemName = ConvertNameDict[item.Name];
  193. }
  194. if (itemName.StartsWith("ValveAV"))
  195. {
  196. var temporaryKey = $"{itemName}.Feedback";
  197. var realKey = $"{ModuleName.PM1}.{temporaryKey}";
  198. if (!btnNameKeyValues.Keys.Contains(temporaryKey))
  199. {
  200. btnNameKeyValues.Add(temporaryKey, item.Value);
  201. }
  202. }
  203. else
  204. {
  205. var temporaryKey = $"{itemName}Enable";
  206. var realKey = $"{ModuleName.PM1}.{temporaryKey}";
  207. if (!btnNameKeyValues.Keys.Contains(temporaryKey))
  208. {
  209. btnNameKeyValues.Add(temporaryKey, item.Value);
  210. }
  211. }
  212. }
  213. foreach (var item in SelectedStep.MFCSets)
  214. {
  215. var temporaryKey = $"{item.ControlName}.Feedback";
  216. var realKey = $"{ModuleName.PM1}.{temporaryKey}";
  217. var recipeValue = double.Parse(item.SetValue.Value);
  218. if (recipeValue > 0)
  219. {
  220. ChangeMfcValue.Add(item.ControlName);
  221. }
  222. btnNameKeyValues.Add(temporaryKey, recipeValue);
  223. temporaryKey = $"{item.ControlName}.Scal";
  224. realKey = $"{ModuleName.PM1}.{temporaryKey}";
  225. if (ScriptVariables.ContainsVariable(realKey))
  226. {
  227. var newvalue = ScriptVariables.GetDoubleByName(realKey);
  228. if (btnNameKeyValues.ContainsKey(realKey))
  229. {
  230. btnNameKeyValues[realKey] = newvalue;
  231. }
  232. else
  233. {
  234. btnNameKeyValues.Add(realKey, newvalue);
  235. }
  236. }
  237. temporaryKey = $"{item.ControlName}.Unit";
  238. realKey = $"{ModuleName.PM1}.{temporaryKey}";
  239. btnNameKeyValues.Add(temporaryKey, item.Unit);
  240. if (ScriptVariables.ContainsVariable(realKey))
  241. {
  242. var newvalue = ScriptVariables.GetStringByName(realKey);
  243. if (btnNameKeyValues.ContainsKey(realKey))
  244. {
  245. btnNameKeyValues[realKey] = newvalue;
  246. }
  247. else
  248. {
  249. btnNameKeyValues.Add(realKey, newvalue);
  250. }
  251. }
  252. }
  253. ScriptVariables.InitializeDefaultSubscriptions(btnNameKeyValues);
  254. }
  255. /// <summary>
  256. /// btn点击事件
  257. /// </summary>
  258. /// <param name="parameter"></param>
  259. public void SwichValue(Dictionary<string, object> parameter)
  260. {
  261. if (SelectedGasStateType == GasPanelStateType.Monitor) return;
  262. var setCmd = (string)parameter["name"];
  263. var showType = (ShowType)parameter["showType"];
  264. var shape = (GasButton)parameter["shape"];
  265. ScriptVariables.IsFetchRT = false;
  266. bool setValue = false;
  267. var status = ScriptVariables.GetBoolByName(shape.DataKey);
  268. setValue = !status;
  269. ScriptVariables.SetBoolByName(shape.DataKey, setValue);
  270. setCmd = ConvertNameDict.ContainsValue(setCmd) ? ConvertNameDict.FirstOrDefault(x => x.Value == setCmd).Key : setCmd;
  271. SelectedStep.ValveSets.FirstOrDefault(x => x.Name == setCmd).SetValue(setValue);
  272. if (!string.IsNullOrEmpty(setCmd))
  273. {
  274. SetValveFollow(setCmd, setValue);
  275. }
  276. }
  277. /// <summary>
  278. /// 阀点击事件
  279. /// </summary>
  280. /// <param name="parameter"></param>
  281. public void ValveTouchUp(Dictionary<string, object> parameter)
  282. {
  283. var shape = (GasAITValve)parameter["shape"];
  284. var name = shape.Name;
  285. if (SelectedGasStateType == GasPanelStateType.Monitor) return;
  286. var status = ScriptVariables.GetBoolByName(shape.Key);
  287. var newStatus = !status;
  288. ScriptVariables.SetBoolByName(shape.Key, newStatus);
  289. InvokeClient.Instance.Service.DoOperation($"{_PM}{name}.{AITValveOperation.GVVirtualTurnValve}", newStatus);
  290. var obj = new object[] { name, AITValveOperation.GVVirtualTurnValve, newStatus };
  291. SetValveCommand(obj);
  292. }
  293. [Subscription("PM1.MFC1.DeviceData")]
  294. public AITMfcData MFC1Data { get; set; }
  295. /// <summary>
  296. /// MFC点击事件
  297. /// </summary>
  298. /// <param name="parameter"></param>
  299. public void MfcFlowTouchUp(Dictionary<string, object> parameter)
  300. {
  301. var shape = (GasAnalogControl4Jet)parameter["shape"];
  302. var name = shape.Name;
  303. if (SelectedGasStateType == GasPanelStateType.Monitor || shape.IsMfm) return;
  304. var setPoint = ScriptVariables.GetVariableByName(shape.ValueKey).DoubleValue;
  305. var maxValue = ScriptVariables.GetVariableByName(shape.MaxValueKey).DoubleValue;
  306. var unit = ScriptVariables.GetVariableByName(shape.UnitKey).StringValue;
  307. InputDialogBox dialogBox = new InputDialogBox
  308. {
  309. TagName = "Number",
  310. CommandDelegate = Execute,
  311. DeviceName = shape.Name,
  312. SetPoint = setPoint,
  313. MaxValue = maxValue,
  314. Unit = unit,
  315. };
  316. dialogBox.SetPoint = Math.Round(setPoint * 100.0, 1);
  317. dialogBox.Owner = WinOwner;
  318. dialogBox.Topmost = false;
  319. dialogBox.WindowStartupLocation = WindowStartupLocation.CenterScreen;
  320. if ((bool)dialogBox.ShowDialog())
  321. {
  322. if (!string.IsNullOrEmpty(dialogBox.InputText))
  323. {
  324. var newValue = double.Parse(dialogBox.InputText);
  325. ScriptVariables.SetDoubleByName(shape.ValueKey, newValue);
  326. shape.Brush = GasMapProvider.ChangeMFCColor;
  327. var obj = new object[] { $"{_PM}{shape.Name}", AITMfcOperation.GVMfcVirtualTurnValve, newValue };
  328. PerformCmdSetMfcFlow(obj);
  329. //if (SelectedGasStateType == GasPanelStateType.Manual)
  330. //{
  331. // obj = new object[] { $"{_PM}{shape.Name}", AITMfcOperation.GVMfcValve, newValue };
  332. // PerformCmdSetMfcFlow(obj);
  333. //}
  334. }
  335. }
  336. dialogBox.Close();
  337. dialogBox.Dispose();
  338. }
  339. private void Execute(double value, double? ramp)
  340. {
  341. }
  342. /// <summary>
  343. /// 下一步/上一步
  344. /// </summary>
  345. /// <param name="cmd"></param>
  346. public void StepClick(string cmd)
  347. {
  348. bool isChangedStep = false;
  349. if (SelectedStep == null)
  350. {
  351. return;
  352. }
  353. switch (cmd)
  354. {
  355. case "PREV":
  356. SelectedStep = CurrentRecipe.Steps.Where(x => x.StepNo == SelectedStep.StepNo - 1).FirstOrDefault();
  357. isChangedStep = true;
  358. break;
  359. case "NEXT":
  360. SelectedStep = CurrentRecipe.Steps.Where(x => x.StepNo == SelectedStep.StepNo + 1).FirstOrDefault();
  361. isChangedStep = true;
  362. break;
  363. default:
  364. break;
  365. }
  366. if (isChangedStep && SelectedStep != null)
  367. {
  368. SelectedStepName = $"{SelectedStep.StepNo}:{SelectedStep.Name}";
  369. SetChangedStep(SelectedStep);
  370. SetValveVirtualFeedbackValue();
  371. }
  372. SetPREVAndNEXTBtn();
  373. }
  374. private void SetPREVAndNEXTBtn()
  375. {
  376. if (SelectedStep != null && CurrentRecipe != null)
  377. {
  378. if (CurrentRecipe.Steps.Count == 0)
  379. {
  380. IsUsePREVBtn = false;
  381. IsUseNEXTBtn = false;
  382. }
  383. else
  384. {
  385. if (SelectedStep.StepNo > CurrentRecipe.Steps[0].StepNo)
  386. {
  387. IsUsePREVBtn = true;
  388. }
  389. else
  390. {
  391. IsUsePREVBtn = false;
  392. }
  393. if (SelectedStep.StepNo < CurrentRecipe.Steps[CurrentRecipe.Steps.Count - 1].StepNo)
  394. {
  395. IsUseNEXTBtn = true;
  396. }
  397. else
  398. {
  399. IsUseNEXTBtn = false;
  400. }
  401. }
  402. }
  403. }
  404. public void SetChangedStep(Step step)
  405. {
  406. if (ChangedStepEvent != null)
  407. {
  408. ChangedStepEvent(step);
  409. }
  410. }
  411. public void SelectedGasStateTypeCmd(string cmd)
  412. {
  413. switch (cmd)
  414. {
  415. case "Manual":
  416. SelectedGasStateType = GasPanelStateType.Manual;
  417. break;
  418. case "Monitor":
  419. SelectedGasStateType = GasPanelStateType.Monitor;
  420. break;
  421. case "Recipe":
  422. SelectedGasStateType = GasPanelStateType.Recipe;
  423. break;
  424. default:
  425. break;
  426. }
  427. SwitchKey(SelectedGasStateType == GasPanelStateType.Monitor);
  428. }
  429. public void SetValveCommand(object param)
  430. {
  431. object[] args = (object[])param;
  432. if (args.Length == 3)
  433. if (SelectedStep != null && SelectedStep.ValveSets.Count > 0 && SelectedStep.ValveSets.FirstOrDefault(x => x.Name == (string)args[0]) != null)
  434. {
  435. SelectedStep.ValveSets.FirstOrDefault(x => x.Name == (string)args[0]).SetValue((bool)args[2]);
  436. //InvokeClient.Instance.Service.DoOperation($"{args[0]}.{args[1]}", args[2]);
  437. // SetValveFollow((string)args[0], (bool)args[2]);
  438. }
  439. //SetCursorPos(0, 0);
  440. }
  441. private void PerformCmdSetMfcFlow(object param)
  442. {
  443. object[] args = (object[])param; //0:devicename, 1:operation, 2:args
  444. if (args.Length == 3)
  445. {
  446. InvokeClient.Instance.Service.DoOperation($"{args[0]}.{args[1]}", args[2]);
  447. if (SelectedStep != null)
  448. {
  449. var mfc = SelectedStep.MFCSets.FirstOrDefault(x => x.ControlName == ((string)args[0]).Replace("PM1.", ""));
  450. if (mfc != null)
  451. {
  452. mfc.SetValue.SetValue(args[2].ToString());
  453. }
  454. }
  455. }
  456. // SetCursorPos(0, 0);
  457. }
  458. private void PerformCmdSetMfmFlow(object param)
  459. {
  460. object[] args = (object[])param; //0:devicename, 1:operation, 2:args
  461. if (args.Length == 3)
  462. {
  463. InvokeClient.Instance.Service.DoOperation($"PM1.{args[0]}.{args[1]}", args[2]);
  464. }
  465. // SetCursorPos(0, 0);
  466. }
  467. public void TempSetSave()
  468. {
  469. foreach (var mfcitem in SelectedStep.MFCSets)
  470. {
  471. var replaceStr = mfcitem.ControlName;
  472. var property = this.GetType().GetProperties().Where(x => x.Name == replaceStr).FirstOrDefault();
  473. if (property == null) continue;
  474. object value = property.GetValue(this, null);
  475. if (value != null)
  476. {
  477. mfcitem.SetValue.Value = ((AnalogDeviceDataItem)value).VirtualFeedBack.ToString();
  478. }
  479. }
  480. ((Window)GetView()).DialogResult = true;
  481. }
  482. public void TempSetCancel()
  483. {
  484. ((Window)GetView()).DialogResult = false;
  485. }
  486. private bool disposed = false;
  487. public void Dispose()
  488. {
  489. Dispose(true);
  490. GC.SuppressFinalize(this); // 防止垃圾回收器再次调用析构函数
  491. }
  492. protected virtual void Dispose(bool disposing)
  493. {
  494. if (!disposed)
  495. {
  496. if (disposing)
  497. {
  498. this.OnDeactivate(true);
  499. // 释放托管资源
  500. }
  501. // 释放非托管资源
  502. disposed = true;
  503. }
  504. }
  505. private void SwichValueBtn(string name, GasButton btn)
  506. {
  507. var dialog = new SwitchValueDialog { };
  508. var status = ScriptVariables.GetBoolByName(btn.DataKey);
  509. dialog.IsOpen = status;
  510. dialog.Owner = WinOwner;
  511. dialog.Topmost = true;
  512. dialog.WindowStartupLocation = WindowStartupLocation.CenterScreen;
  513. dialog.DeviceName = $"Swich {name}";
  514. dialog.ShowDialog();
  515. if ((bool)dialog.IsSave)
  516. {
  517. string setCmd = name.Replace("Enable", "");
  518. ScriptVariables.SetBoolByName(btn.DataKey, dialog.IsOpen);
  519. SelectedStep.ValveSets.FirstOrDefault(x => x.Name == setCmd).Value = dialog.IsOpen;
  520. if (!string.IsNullOrEmpty(setCmd))
  521. {
  522. SetValveFollow(setCmd, dialog.IsOpen);
  523. }
  524. }
  525. }
  526. private void SetHeaterBtn(string name, GasButton btn)
  527. {
  528. ScriptVariables.IsFetchRT = false;
  529. string setCmd = "";
  530. bool setValue = false;
  531. var status = ScriptVariables.GetBoolByName(btn.DataKey);
  532. setCmd = name.Replace("Enable", "");
  533. setValue = !status;
  534. ScriptVariables.SetBoolByName(btn.DataKey, setValue);
  535. SelectedStep.ValveSets.FirstOrDefault(x => x.Name == setCmd).SetValue(setValue);
  536. if (!string.IsNullOrEmpty(setCmd))
  537. {
  538. SetValveFollow(setCmd, setValue);
  539. }
  540. }
  541. private void SelectPumpBtn(string name, GasButton btn)
  542. {
  543. ScriptVariables.IsFetchRT = false;
  544. var isConfirm = DialogBox.Confirm($"Are you sure change {name} status?");
  545. if (isConfirm)
  546. {
  547. string setCmd = "";
  548. bool setValue = false;
  549. //if (name == "DP1Enable")
  550. //{
  551. // name = "DPEnable";
  552. // btn.DataKey = name;
  553. //}
  554. var status = ScriptVariables.GetBoolByName(btn.DataKey);
  555. setCmd = name.Replace("Enable", "");
  556. setValue = !status;
  557. ScriptVariables.SetBoolByName(btn.DataKey, setValue);
  558. SelectedStep.ValveSets.FirstOrDefault(x => x.Name.ToUpper() == setCmd.ToUpper()).SetValue(setValue);
  559. if (!string.IsNullOrEmpty(setCmd))
  560. {
  561. SetValveFollow(setCmd, setValue);
  562. }
  563. }
  564. }
  565. private void SetValveFollow(string controlName, bool value)
  566. {
  567. int firstIndex = CurrentRecipe.Steps.IndexOf(SelectedStep);
  568. if (firstIndex < CurrentRecipe.Steps.Count)
  569. {
  570. for (int i = firstIndex + 1; i < CurrentRecipe.Steps.Count; i++)
  571. {
  572. if (!CurrentRecipe.Steps[i].ValveIsSaved)
  573. {
  574. break;
  575. }
  576. else
  577. {
  578. CurrentRecipe.Steps[i].ValveSets.FirstOrDefault(x => x.Name == controlName).Value = value;
  579. }
  580. }
  581. }
  582. }
  583. }
  584. }