RecipeViewModel.cs 71 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709
  1. using Aitex.Core.Common.DeviceData;
  2. using Aitex.Core.RT.IOCore;
  3. using Aitex.Core.RT.Log;
  4. using Aitex.Core.UI.View.Common;
  5. using MECF.Framework.Common.DataCenter;
  6. using MECF.Framework.Common.OperationCenter;
  7. using Microsoft.VisualBasic;
  8. using Newtonsoft.Json;
  9. using Newtonsoft.Json.Linq;
  10. using Prism.Commands;
  11. using Prism.Mvvm;
  12. using System;
  13. using System.Collections.Generic;
  14. using System.Collections.ObjectModel;
  15. using System.IO;
  16. using System.Linq;
  17. using System.Reflection;
  18. using System.Text;
  19. using System.Threading.Tasks;
  20. using System.Windows;
  21. using System.Windows.Controls;
  22. using System.Windows.Data;
  23. using System.Windows.Input;
  24. using System.Windows.Media;
  25. using System.Xml;
  26. using Venus_Core;
  27. using Venus_Core.Attributes;
  28. using Venus_MainPages.PMs;
  29. using Venus_MainPages.Unity;
  30. using Venus_MainPages.Views;
  31. using Venus_Themes.UserControls;
  32. using WPF.Themes.UserControls;
  33. using MessageBox = System.Windows.MessageBox;
  34. using RecipeStep = Venus_Core.RecipeStep;
  35. namespace Venus_MainPages.ViewModels
  36. {
  37. internal class RecipeViewModel : BindableBase
  38. {
  39. #region 私有字段
  40. public string ModuleName = "PMA";
  41. private string m_CurrentRecipeName;
  42. private UiRecipeManager m_uiRecipeManager = new UiRecipeManager();
  43. private RecipeView recipeView;
  44. private TreeView treeViewRcpList;
  45. private Recipe m_currentRecipe;
  46. private string m_recipeType;
  47. private bool firstLoad = true;
  48. private WrapPanel headWrapPanel;
  49. private int copyIndex = -1;
  50. private List<string> EPDCfgList = new List<string>();
  51. private EPDType currentEPDType = EPDType.None;
  52. private JetChamber currentChamber;
  53. private bool isInstalledEPD;
  54. private bool m_IsFrozen;
  55. private bool m_PMAIsInstalled;
  56. private bool m_PMBIsInstalled;
  57. private bool m_PMCIsInstalled;
  58. private bool m_PMDIsInstalled;
  59. private List<string> moduleList = new List<string>();
  60. TreeViewFileItem selectedItem;
  61. private string typeFolder = "";
  62. private bool m_HeadExpand = true;
  63. private Grid leftGrid;
  64. private Grid rightGrid;
  65. private int controlHeight = 24;
  66. #endregion
  67. #region 属性
  68. public bool HeadExpand
  69. {
  70. get { return m_HeadExpand; }
  71. set { SetProperty(ref m_HeadExpand, value); }
  72. }
  73. public string CurrentRecipeName
  74. {
  75. get { return m_CurrentRecipeName; }
  76. set { SetProperty(ref m_CurrentRecipeName, value); }
  77. }
  78. public Recipe CurrentRecipe
  79. {
  80. get { return m_currentRecipe; }
  81. set
  82. {
  83. m_currentRecipe = value;
  84. RecipeType = m_currentRecipe?.Header?.Type.ToString();
  85. }
  86. }
  87. public string RecipeType
  88. {
  89. get { return m_recipeType; }
  90. set { SetProperty(ref m_recipeType, value); }
  91. }
  92. public bool IsFrozen
  93. {
  94. get { return m_IsFrozen; }
  95. set { SetProperty(ref m_IsFrozen, value); }
  96. }
  97. public bool PMAIsInstalled
  98. {
  99. get { return m_PMAIsInstalled; }
  100. set { SetProperty(ref m_PMAIsInstalled, value); }
  101. }
  102. public bool PMBIsInstalled
  103. {
  104. get { return m_PMBIsInstalled; }
  105. set { SetProperty(ref m_PMBIsInstalled, value); }
  106. }
  107. public bool PMCIsInstalled
  108. {
  109. get { return m_PMCIsInstalled; }
  110. set { SetProperty(ref m_PMCIsInstalled, value); }
  111. }
  112. public bool PMDIsInstalled
  113. {
  114. get { return m_PMDIsInstalled; }
  115. set { SetProperty(ref m_PMDIsInstalled, value); }
  116. }
  117. #endregion
  118. #region 命令
  119. private DelegateCommand<Object> _MouseRightButtonDownCommand;
  120. public DelegateCommand<Object> MouseRightButtonDownCommand =>
  121. _MouseRightButtonDownCommand ?? (_MouseRightButtonDownCommand = new DelegateCommand<Object>(OnMouseRightButtonDown));
  122. private DelegateCommand<Object> _LoadedCommand;
  123. public DelegateCommand<Object> LoadedCommand =>
  124. _LoadedCommand ?? (_LoadedCommand = new DelegateCommand<Object>(OnLoaded));
  125. private DelegateCommand _SaveRecipeCommand;
  126. public DelegateCommand SaveRecipeCommand =>
  127. _SaveRecipeCommand ?? (_SaveRecipeCommand = new DelegateCommand(OnSaveRecipe));
  128. private DelegateCommand<object> _SaveToRecipeCommand;
  129. public DelegateCommand<object> SaveToRecipeCommand =>
  130. _SaveToRecipeCommand ?? (_SaveToRecipeCommand = new DelegateCommand<object>(OnSaveToRecipe));
  131. private DelegateCommand _AddStepCommand;
  132. public DelegateCommand AddStepCommand =>
  133. _AddStepCommand ?? (_AddStepCommand = new DelegateCommand(OnAddStep));
  134. private DelegateCommand _DeleteStepCommand;
  135. public DelegateCommand DeleteStepCommand =>
  136. _DeleteStepCommand ?? (_DeleteStepCommand = new DelegateCommand(OnDeleteStep));
  137. private DelegateCommand _RefreshCommand;
  138. public DelegateCommand RefreshCommand =>
  139. _RefreshCommand ?? (_RefreshCommand = new DelegateCommand(OnRefresh));
  140. private DelegateCommand _ExpandCommand;
  141. public DelegateCommand ExpandCommand =>
  142. _ExpandCommand ?? (_ExpandCommand = new DelegateCommand(OnExpand));
  143. private DelegateCommand _UnloadCommand;
  144. public DelegateCommand UnloadCommand =>
  145. _UnloadCommand ?? (_UnloadCommand = new DelegateCommand(OnUnload));
  146. private DelegateCommand _ClearRecipeCommand;
  147. public DelegateCommand ClearRecipeCommand =>
  148. _ClearRecipeCommand ?? (_ClearRecipeCommand = new DelegateCommand(OnClearRecipe));
  149. private DelegateCommand<Object> _MouseLeftButtonDownCommand;
  150. public DelegateCommand<Object> MouseLeftButtonDownCommand =>
  151. _MouseLeftButtonDownCommand ?? (_MouseLeftButtonDownCommand = new DelegateCommand<Object>(OnMouseLeftButtonDown));
  152. #endregion
  153. #region 命令方法
  154. private void OnAddStep()
  155. {
  156. if (CurrentRecipe != null)
  157. {
  158. var index = rightGrid.ColumnDefinitions.Count;
  159. RecipeStep recipeStep;
  160. if (copyIndex == -1)
  161. {
  162. recipeStep = new RecipeStep();
  163. recipeStep.StepNo = index + 1;
  164. recipeStep.LstUnit = RecipeUnity.GetAllUnits(currentChamber, CurrentRecipe.Header.Type);
  165. CurrentRecipe.Steps.Add(recipeStep);
  166. }
  167. else
  168. {
  169. var t = JsonConvert.SerializeObject(CurrentRecipe);
  170. recipeStep = Recipe.Load(t).Steps[copyIndex - 1];
  171. recipeStep.StepNo = index + 1;
  172. CurrentRecipe.Steps.Add(recipeStep);
  173. }
  174. ColumnDefinition col1 = new ColumnDefinition();
  175. col1.Width = GridLength.Auto;
  176. rightGrid.ColumnDefinitions.Insert(index, col1);
  177. RecipeStepToGridColumn(recipeStep, rightGrid, index);
  178. }
  179. }
  180. private void OnDeleteStep()
  181. {
  182. if (CurrentRecipe != null)
  183. {
  184. OnDeleteStep(CurrentRecipe.Steps.Count - 1);
  185. }
  186. }
  187. private void OnSaveRecipe()
  188. {
  189. if (WPFMessageBox.ShowQuestion($"Save recipe file?", "") == MessageBoxResult.Yes)
  190. {
  191. var inUseRecipe = QueryDataClient.Instance.Service.GetData($"Scheduler.InUsingRecipe");
  192. if (inUseRecipe != null)
  193. {
  194. if ((inUseRecipe as List<string>).Contains($"{ModuleName}.{CurrentRecipe.Header.Type}.{CurrentRecipeName}"))
  195. {
  196. WPFMessageBox.ShowError($"{CurrentRecipeName} Recipe is In Use,can not edit");
  197. return;
  198. }
  199. }
  200. }
  201. CurrentRecipe.Header.EditTime = DateTime.Now.ToString();
  202. //SaveRecipe(CurrentRecipeName, RecipeUnity.RecipeToString(CurrentRecipe));
  203. var newrecipePath = Path.Combine(QueryDataClient.Instance.Service.GetData("GetRTPath").ToString(), "Recipes", ModuleName, typeFolder, CurrentRecipeName + ".rcp");
  204. FileInfo fi = new FileInfo(newrecipePath);
  205. var di = fi.Directory;
  206. if (!di.Exists)
  207. {
  208. di.Create();
  209. }
  210. //File.WriteAllText(newrecipePath, RecipeUnity.RecipeToString(CurrentRecipe),Encoding.UTF8);
  211. string recipeContent = RecipeUnity.RecipeToString(CurrentRecipe);
  212. for (int index = 0; index < CurrentRecipe.Steps.Count; index++)
  213. {
  214. if (CurrentRecipe.Steps[index].Type == StepType.OverEtch)
  215. {
  216. if (index == 0)
  217. {
  218. WPFMessageBox.ShowError($"{CurrentRecipeName} Recipe has first item type is OverEtch");
  219. return;
  220. }
  221. if (CurrentRecipe.Steps[index - 1].Type != StepType.EndPoint)
  222. {
  223. WPFMessageBox.ShowError($"{CurrentRecipeName} Recipe contains steps not EndPoint before OverEtch");
  224. return;
  225. }
  226. }
  227. }
  228. SaveRecipe(CurrentRecipe.Header.Name, CurrentRecipe.Header.Type.ToString(), recipeContent);
  229. //LoadHeadWrapPanel(headWrapPanel, CurrentRecipe);
  230. SaveEAPRecipe(recipeContent, CurrentRecipe.Steps);
  231. }
  232. private void SaveEAPRecipe(string recipeContent, ObservableCollection<RecipeStep> Steps)
  233. {
  234. if (currentChamber == JetChamber.Kepler2200A || currentChamber == JetChamber.Kepler2200B)
  235. {
  236. var newrecipePath2 = Path.Combine(QueryDataClient.Instance.Service.GetData("GetRTPath").ToString(), "Recipes", ModuleName, $"{typeFolder}_EAP", CurrentRecipeName + ".rcp");
  237. FileInfo fi2 = new FileInfo(newrecipePath2);
  238. var di2 = fi2.Directory;
  239. if (!di2.Exists)
  240. {
  241. di2.Create();
  242. }
  243. var newContent = Recipe.ShowEAPRecipe(recipeContent, CurrentRecipe.Steps);
  244. File.WriteAllText(newrecipePath2, newContent, Encoding.UTF8);
  245. }
  246. }
  247. private void OnSaveToRecipe(object obj)
  248. {
  249. if (CurrentRecipe == null)
  250. {
  251. return;
  252. }
  253. string moduleName = "";
  254. switch (obj.ToString())
  255. {
  256. case "0":
  257. moduleName = "PMA";
  258. break;
  259. case "1":
  260. moduleName = "PMB";
  261. break;
  262. case "2":
  263. moduleName = "PMC";
  264. break;
  265. case "3":
  266. moduleName = "PMD";
  267. break;
  268. case "4":
  269. moduleName = "ALL";
  270. break;
  271. }
  272. if (moduleName == "")
  273. {
  274. return;
  275. }
  276. if (moduleName == "ALL")
  277. {
  278. var newName = Interaction.InputBox(" ", $"Save Recipe To All", CurrentRecipeName, -1, -1);
  279. OnSaveRecipe();
  280. foreach (var x in moduleList)
  281. {
  282. if (newName != "")
  283. {
  284. var targetChamber = (JetChamber)Enum.Parse(typeof(JetChamber), QueryDataClient.Instance.Service.GetConfig($"{x}.ChamberType").ToString());
  285. if (currentChamber != targetChamber || x == ModuleName)
  286. {
  287. continue;
  288. }
  289. var newRecipe = CurrentRecipe;
  290. newRecipe.Header.Name = newName;
  291. newRecipe.Header.CreateTime = DateTime.Now.ToString();
  292. var newrecipePath = Path.Combine(QueryDataClient.Instance.Service.GetData("GetRTPath").ToString(), "Recipes", x, typeFolder, newName + ".rcp");
  293. FileInfo fi = new FileInfo(newrecipePath);
  294. var di = fi.Directory;
  295. if (!di.Exists)
  296. {
  297. di.Create();
  298. }
  299. //File.WriteAllText(newrecipePath, RecipeUnity.RecipeToString(newRecipe));
  300. if (m_uiRecipeManager.SaveAsRecipeWithType(x, CurrentRecipe.Header.Type.ToString(), newName, RecipeUnity.RecipeToString(newRecipe)))
  301. {
  302. UpdateRecipeFileList();
  303. }
  304. UpdateRecipeFileList();
  305. }
  306. }
  307. }
  308. else
  309. {
  310. var targetChamber = (JetChamber)Enum.Parse(typeof(JetChamber), QueryDataClient.Instance.Service.GetConfig($"{moduleName}.ChamberType").ToString());
  311. if (currentChamber != targetChamber)
  312. {
  313. WPFMessageBox.ShowError($"Recipe can not from {currentChamber.ToString()} copy to {targetChamber.ToString()}");
  314. return;
  315. }
  316. var newName = Interaction.InputBox(" ", $"Save Recipe To {moduleName}", CurrentRecipeName, -1, -1);
  317. if (newName != "")
  318. {
  319. OnSaveRecipe();
  320. var newRecipe = CurrentRecipe;
  321. newRecipe.Header.Name = newName;
  322. newRecipe.Header.CreateTime = DateTime.Now.ToString();
  323. var newrecipePath = Path.Combine(QueryDataClient.Instance.Service.GetData("GetRTPath").ToString(), "Recipes", moduleName, typeFolder, newName + ".rcp");
  324. FileInfo fi = new FileInfo(newrecipePath);
  325. var di = fi.Directory;
  326. if (!di.Exists)
  327. {
  328. di.Create();
  329. }
  330. //File.WriteAllText(newrecipePath, RecipeUnity.RecipeToString(newRecipe));
  331. if (m_uiRecipeManager.SaveAsRecipeWithType(moduleName, CurrentRecipe.Header.Type.ToString(), newName, RecipeUnity.RecipeToString(newRecipe)))
  332. {
  333. UpdateRecipeFileList();
  334. }
  335. //if (SaveAsRecipeWithType(newName, CurrentRecipe.Header.Type.ToString(), RecipeUnity.RecipeToString(newRecipe)))
  336. //{
  337. //}
  338. }
  339. }
  340. }
  341. private async void OnLoaded(Object myrecipeView)
  342. {
  343. if (firstLoad == true)
  344. {
  345. currentChamber = (JetChamber)Enum.Parse(typeof(JetChamber), QueryDataClient.Instance.Service.GetConfig($"{ModuleName}.ChamberType").ToString());
  346. if (currentChamber != JetChamber.Kepler2200A && currentChamber != JetChamber.Kepler2200B)
  347. {
  348. isInstalledEPD = bool.Parse(QueryDataClient.Instance.Service.GetConfig($"{ModuleName}.EPD.IsEnabled").ToString());
  349. }
  350. firstLoad = false;
  351. recipeView = myrecipeView as RecipeView;
  352. treeViewRcpList = recipeView.treeViewRcpList;
  353. headWrapPanel = recipeView.headWrapPanel;
  354. //bodyStackPanel = recipeView.bodyStackPanel;
  355. leftGrid = recipeView.leftGrid;
  356. rightGrid = recipeView.rightGrid;
  357. UpdateRecipeFileList();
  358. treeViewRcpList.SelectedItemChanged += TreeViewRcpList_SelectedItemChanged;
  359. string allModules = QueryDataClient.Instance.Service.GetConfig($"System.InstalledModules").ToString();
  360. if (allModules.Contains("PMA"))
  361. {
  362. PMAIsInstalled = true;
  363. moduleList.Add("PMA");
  364. }
  365. if (allModules.Contains("PMB"))
  366. {
  367. PMBIsInstalled = true;
  368. moduleList.Add("PMB");
  369. }
  370. if (allModules.Contains("PMC"))
  371. {
  372. PMCIsInstalled = true;
  373. moduleList.Add("PMC");
  374. }
  375. if (allModules.Contains("PMD"))
  376. {
  377. PMDIsInstalled = true;
  378. moduleList.Add("PMD");
  379. }
  380. }
  381. if (isInstalledEPD)
  382. {
  383. for (int i = 0; i < 5; i++)
  384. {
  385. InvokeClient.Instance.Service.DoOperation($"{ModuleName}.EndPoint.SearchCfg");
  386. await Task.Delay(200);
  387. currentEPDType = (EPDType)System.Convert.ToInt32(QueryDataClient.Instance.Service.GetConfig($"{ModuleName}.EPD.EPDType"));
  388. if (currentEPDType == EPDType.Socket)
  389. {
  390. EPDCfgList = (List<string>)QueryDataClient.Instance.Service.GetData($"{ModuleName}.EPDCfgList");
  391. }
  392. if (EPDCfgList != null)
  393. {
  394. EPDCfgList.Add("");
  395. break;
  396. }
  397. }
  398. }
  399. UpdateRecipeFileList();
  400. }
  401. private void TreeViewRcpList_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
  402. {
  403. //rightGrid.Visibility = Visibility.Visible;
  404. selectedItem = e.NewValue as TreeViewFileItem;
  405. if (selectedItem == null)
  406. return;
  407. try
  408. {
  409. string[] info = selectedItem.FileName.Split('\\');
  410. //string path;
  411. string xmlRecipeData = "";
  412. if (info.Length == 1)
  413. {
  414. CurrentRecipeName = info[0];
  415. typeFolder = "";
  416. string path = Path.Combine(QueryDataClient.Instance.Service.GetData("GetRTPath").ToString(), "Recipes", ModuleName, $"{CurrentRecipeName}.rcp");
  417. xmlRecipeData = m_uiRecipeManager.LoadRecipeByPath(path);
  418. }
  419. else if (info.Length == 2)
  420. {
  421. string type = info[0];
  422. typeFolder = type;
  423. CurrentRecipeName = info[1];
  424. string path = Path.Combine(QueryDataClient.Instance.Service.GetData("GetRTPath").ToString(), "Recipes", ModuleName, type, $"{CurrentRecipeName}.rcp");
  425. xmlRecipeData = m_uiRecipeManager.LoadRecipeByPath(path);
  426. }
  427. else
  428. {
  429. return;
  430. }
  431. if (xmlRecipeData == "")
  432. {
  433. treeViewRcpList.Items.Remove(selectedItem);
  434. return;
  435. }
  436. CurrentRecipe = Recipe.Load(xmlRecipeData);
  437. if (CurrentRecipe.Header.ChamberType != currentChamber)
  438. {
  439. WPFMessageBox.ShowError($"Can not Open {CurrentRecipe.Header.ChamberType} Recipe in {currentChamber} Chamber,please delete it.");
  440. return;
  441. }
  442. LoadHeadWrapPanel(headWrapPanel, CurrentRecipe);
  443. LoadRecipe(CurrentRecipe);
  444. }
  445. catch (Exception ex)
  446. {
  447. MessageBox.Show(string.Format(Application.Current.Resources["GlobalLableTitleRecipeEditor"].ToString(), ex.Message), Application.Current.Resources["GlobalLableTitleRecipeEditor"].ToString(), MessageBoxButton.OK, MessageBoxImage.Error);
  448. }
  449. e.Handled = true;
  450. }
  451. public bool SaveRecipe(string recipeName, string type, string recipeContent)
  452. {
  453. return m_uiRecipeManager.SaveRecipeWithType(ModuleName, type, recipeName, recipeContent);
  454. }
  455. private void OnMouseRightButtonDown(Object treeView)
  456. {
  457. //treeViewRcpList = treeView as TreeView;
  458. treeViewRcpList.ContextMenu = new ContextMenu() { Background = new SolidColorBrush(Colors.AliceBlue) };
  459. MenuItem menuItem = new MenuItem();
  460. menuItem = new MenuItem();
  461. menuItem.Tag = "\\";
  462. menuItem.Click += new RoutedEventHandler(menuItem_MouseClick_CreateRecipe);
  463. menuItem.Header = "New Recipe";
  464. treeViewRcpList.ContextMenu.Items.Add(menuItem);
  465. menuItem = new MenuItem();
  466. menuItem.Tag = "\\";
  467. menuItem.Click += new RoutedEventHandler(menuItem_MouseClick_DeleteRecipe);
  468. menuItem.Header = "Delete Recipe";
  469. treeViewRcpList.ContextMenu.Items.Add(menuItem);
  470. menuItem = new MenuItem();
  471. menuItem.Tag = "\\";
  472. menuItem.Click += new RoutedEventHandler(menuItem_MouseClick_SaveAsRecipe);
  473. menuItem.Header = "Save As Recipe";
  474. treeViewRcpList.ContextMenu.Items.Add(menuItem);
  475. menuItem = new MenuItem();
  476. menuItem.Tag = "\\";
  477. menuItem.Click += new RoutedEventHandler(menuItem_MouseClick_RenameRecipe);
  478. menuItem.Header = "Rename";
  479. treeViewRcpList.ContextMenu.Items.Add(menuItem);
  480. treeViewRcpList.ContextMenu.Visibility = Visibility.Visible;
  481. }
  482. private void OnMouseLeftButtonDown(Object treeView)
  483. {
  484. //treeViewRcpList = treeView as TreeView;
  485. }
  486. private void menuItem_MouseClick_CreateRecipe(object sender, RoutedEventArgs e)
  487. {
  488. MenuItem mit = sender as MenuItem;
  489. string folderName = mit.Tag as string;
  490. PerformCreateRecipe(folderName);
  491. }
  492. private void PerformCreateRecipe(string folderName)
  493. {
  494. try
  495. {
  496. bool hasHV = false;
  497. if (currentChamber == JetChamber.VenusSE || currentChamber == JetChamber.VenusDE)
  498. {
  499. hasHV = true;
  500. }
  501. RecipeNameInputDlg dlg = new RecipeNameInputDlg(Application.Current.Resources["GlobalLableMsgInputRecipeName"].ToString(), hasHV)
  502. {
  503. Owner = Application.Current.MainWindow
  504. };
  505. if (dlg.ShowDialog() == true)
  506. {
  507. var recipeName = dlg.InputText;
  508. //var recipeName = folderName + dlg.InputText;
  509. //var recipeName = folderName + "\\" + dlg.InputText;
  510. if (!RecipeNameIsOk(recipeName))
  511. {
  512. return;
  513. }
  514. RecipeType type = (RecipeType)Enum.Parse(typeof(RecipeType), dlg.SelectedType);
  515. string newRecipe = RecipeUnity.CreateRecipe(currentChamber, type, dlg.InputText);
  516. if (SaveAsRecipeWithType(recipeName, type.ToString(), newRecipe))
  517. {
  518. UpdateRecipeFileList();
  519. }
  520. }
  521. }
  522. catch (Exception ex)
  523. {
  524. LOG.WriteExeption(ex);
  525. MessageBox.Show(string.Format(Application.Current.Resources["GlobalLableMsgRecipeCreateException"].ToString(), ex.Message), Application.Current.Resources["GlobalLableTitleRecipeEditor"].ToString(), MessageBoxButton.OK, MessageBoxImage.Error);
  526. }
  527. }
  528. private void menuItem_MouseClick_DeleteRecipe(object sender, RoutedEventArgs e)
  529. {
  530. //if (CurrentRecipe == null)
  531. //{
  532. // return;
  533. //}
  534. if (WPFMessageBox.ShowQuestion($"Delete {typeFolder}Recipe {CurrentRecipeName}?", "删除后无法恢复!!!") == MessageBoxResult.Yes)
  535. {
  536. MenuItem mit = sender as MenuItem;
  537. //string recipename = mit.Header.ToString();
  538. string path = typeFolder == "" ? CurrentRecipeName : $"{typeFolder}\\{CurrentRecipeName}";
  539. m_uiRecipeManager.DeleteRecipe(ModuleName, path);
  540. //PerformCreateRecipe(folderName);
  541. //treeViewRcpList.Items.Remove(selectedItem);
  542. UpdateRecipeFileList();
  543. }
  544. }
  545. private void menuItem_MouseClick_SaveAsRecipe(object sender, RoutedEventArgs e)
  546. {
  547. if (CurrentRecipe == null)
  548. {
  549. return;
  550. }
  551. var newName = Interaction.InputBox(" ", "Save As Recipe", CurrentRecipeName, -1, -1);
  552. if (!RecipeNameIsOk(newName))
  553. {
  554. return;
  555. }
  556. //newName = newName.Trim();
  557. if (newName != CurrentRecipeName && newName != "")
  558. {
  559. var newRecipe = CurrentRecipe;
  560. if (WPFMessageBox.ShowQuestion($"Save recipe file {newName} ?", "") == MessageBoxResult.Yes)
  561. {
  562. //MessageBox.Show($"Save as recipe {newName} ?", "Save As Recipe", MessageBoxButton.OKCancel, MessageBoxImage.Warning);
  563. newRecipe.Header.Name = newName;
  564. newRecipe.Header.CreateTime = DateTime.Now.ToString();
  565. //var newrecipePath = Path.Combine(QueryDataClient.Instance.Service.GetData("GetRTPath").ToString(), "Recipes", ModuleName, typeFolder, newName + ".rcp");
  566. //File.WriteAllText(newrecipePath, RecipeUnity.RecipeToString(newRecipe));
  567. if (SaveAsRecipeWithType(newName, CurrentRecipe.Header.Type.ToString(), RecipeUnity.RecipeToString(newRecipe)))
  568. {
  569. UpdateRecipeFileList();
  570. CurrentRecipeName = newName;
  571. //LoadHeadWrapPanel(headWrapPanel, CurrentRecipe);
  572. LoadRecipe(CurrentRecipe);
  573. }
  574. }
  575. }
  576. else if (newName == CurrentRecipeName || newName == "")
  577. {
  578. WPFMessageBox.Show("Please input right recipename", MessageBoxButton.OK);
  579. }
  580. }
  581. private void menuItem_MouseClick_RenameRecipe(object sender, RoutedEventArgs e)
  582. {
  583. if (CurrentRecipe == null)
  584. {
  585. return;
  586. }
  587. var newName = Interaction.InputBox(" ", "Rename Recipe", CurrentRecipeName, -1, -1);
  588. //newName = newName.Trim();
  589. if (!RecipeNameIsOk(newName))
  590. {
  591. return;
  592. }
  593. if (newName != CurrentRecipeName && newName != "")
  594. {
  595. var newRecipe = CurrentRecipe;
  596. if (WPFMessageBox.ShowQuestion($"Save recipe file {newName} ?", "") == MessageBoxResult.Yes)
  597. {
  598. newRecipe.Header.Name = newName;
  599. newRecipe.Header.CreateTime = DateTime.Now.ToString();
  600. var oldrecipePath = Path.Combine(QueryDataClient.Instance.Service.GetData("GetRTPath").ToString(), "Recipes", ModuleName, typeFolder, CurrentRecipeName + ".rcp");
  601. var newrecipePath = Path.Combine(QueryDataClient.Instance.Service.GetData("GetRTPath").ToString(), "Recipes", ModuleName, typeFolder, newName + ".rcp");
  602. File.Delete(oldrecipePath);
  603. File.WriteAllText(newrecipePath, RecipeUnity.RecipeToString(newRecipe));
  604. UpdateRecipeFileList();
  605. }
  606. }
  607. else if (newName == CurrentRecipeName || newName == "")
  608. {
  609. WPFMessageBox.Show("Please input right recipename", MessageBoxButton.OK);
  610. }
  611. }
  612. public bool SaveAsRecipeWithType(string recipeName, string type, string recipeContent)
  613. {
  614. return m_uiRecipeManager.SaveAsRecipeWithType(ModuleName, type, recipeName, recipeContent);
  615. }
  616. public string GetXmlRecipeList()
  617. {
  618. return m_uiRecipeManager.GetXmlRecipeList(ModuleName, true) ?? "";
  619. }
  620. void CreateTreeViewItems(XmlElement curElementNode, ItemsControl itemsControl)
  621. {
  622. foreach (XmlElement ele in curElementNode.ChildNodes)
  623. {
  624. if (ele.Name == "File")
  625. {
  626. string fileName = ele.Attributes["Name"].Value;
  627. fileName = fileName.Substring(fileName.LastIndexOf('\\') + 1);
  628. TreeViewFileItem item = new TreeViewFileItem(ele.Attributes["Name"].Value);
  629. item.Tag = ele.Attributes["Name"].Value;
  630. if (!item.Tag.ToString().Contains("\\"))
  631. {
  632. continue;
  633. }
  634. itemsControl.Items.Add(item);
  635. }
  636. else if (ele.Name == "Folder")
  637. {
  638. string folderName = ele.Attributes["Name"].Value;
  639. folderName = folderName.Substring(folderName.LastIndexOf('\\') + 1);
  640. if (folderName == Venus_Core.RecipeType.Process.ToString() || folderName == Venus_Core.RecipeType.Clean.ToString() || folderName == Venus_Core.RecipeType.Chuck.ToString() || folderName == Venus_Core.RecipeType.DeChuck.ToString())
  641. {
  642. TreeViewFolderItem item = new TreeViewFolderItem(folderName);
  643. item.Tag = ele.Attributes["Name"].Value;
  644. CreateTreeViewItems(ele, item);
  645. item.IsExpanded = false;
  646. itemsControl.Items.Add(item);
  647. }
  648. }
  649. }
  650. }
  651. private IEnumerable<string> GetFilesNames(string path)
  652. {
  653. if (Directory.Exists(path))
  654. {
  655. return Directory.GetFiles(path, "*.rcp")?
  656. .Select(Path.GetFileNameWithoutExtension);
  657. }
  658. else
  659. {
  660. return new List<string>();
  661. }
  662. }
  663. private void LoadHeadWrapPanel(WrapPanel HeadWrapPanel, Recipe recipe)
  664. {
  665. HeadWrapPanel.Children.Clear();
  666. Type type = recipe.Header.GetType();
  667. foreach (var propertyInfo in type.GetProperties())
  668. {
  669. TextBlock textBlock = new TextBlock();
  670. textBlock.FontSize = 16;
  671. textBlock.Margin = new Thickness(0, 20, 0, 0);
  672. textBlock.Width = 200;
  673. if (currentChamber != JetChamber.VenusDE && propertyInfo.Name == "WallTemperature")
  674. {
  675. continue;
  676. }
  677. if ((currentChamber == JetChamber.VenusDE || currentChamber == JetChamber.VenusSE) && propertyInfo.Name == "Barcode")
  678. {
  679. continue;
  680. }
  681. switch (propertyInfo.Name)
  682. {
  683. case "ChuckRecipe":
  684. if (currentChamber != JetChamber.VenusSE && currentChamber != JetChamber.VenusDE)
  685. {
  686. continue;
  687. }
  688. textBlock.Text = "Chuck:";
  689. break;
  690. case "DechuckRecipe":
  691. if (currentChamber != JetChamber.VenusSE && currentChamber != JetChamber.VenusDE)
  692. {
  693. continue;
  694. }
  695. textBlock.Text = "DeChuck:";
  696. break;
  697. default:
  698. object[] NameAttrs = propertyInfo.GetCustomAttributes(typeof(CustomName), true);
  699. string name;
  700. if (NameAttrs.Length > 0)
  701. {
  702. name = (NameAttrs[0] as CustomName).Name;
  703. }
  704. else
  705. {
  706. name = propertyInfo.Name;
  707. }
  708. textBlock.Text = name + ":";
  709. break;
  710. }
  711. textBlock.Margin = new Thickness(15, 0, 0, 0);
  712. textBlock.VerticalAlignment = VerticalAlignment.Center;
  713. HeadWrapPanel.Children.Add(textBlock);
  714. Binding binding = new Binding()
  715. {
  716. Source = recipe.Header, // 数据源
  717. Path = new PropertyPath(propertyInfo.Name), // 需绑定的数据源属性名
  718. Mode = BindingMode.TwoWay, // 绑定模式
  719. UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged, //触发器
  720. };
  721. var propertyTypeName = propertyInfo.PropertyType.Name;
  722. var propertyInfoName = propertyInfo.Name;
  723. Control control = new Control();
  724. switch (propertyInfoName)
  725. {
  726. case "ChamberType":
  727. control = new ComboBox();
  728. control.IsEnabled = false;
  729. //control.Height = 23;
  730. control.SetBinding(ComboBox.SelectedItemProperty, binding);
  731. control.Style = (Style)recipeView.FindResource("customeComboBoxStyle");
  732. ItemsControlHelper.SetEnumValuesToItemsSource(control, true);
  733. break;
  734. case "Type":
  735. ComboBox cb = new ComboBox();
  736. cb.Style = (Style)recipeView.FindResource("customeComboBoxStyle");
  737. cb.IsEnabled = false;
  738. cb.SelectionChanged += ChangeUI;
  739. control = cb;
  740. //control.Height = 23;
  741. ItemsControlHelper.SetEnumValuesToItemsSource(control, true);
  742. control.SetBinding(ComboBox.SelectedItemProperty, binding);
  743. break;
  744. case "ChuckRecipe":
  745. StringBuilder stringBuilder = new StringBuilder();
  746. control = new ComboBox()
  747. {
  748. ItemsSource = GetFilesNames(Path.Combine(QueryDataClient.Instance.Service.GetData("GetRTPath").ToString(), "Recipes", $"{ModuleName}\\Chuck"))
  749. };
  750. //control.Height = 23;
  751. control.MinWidth = 100;
  752. control.MaxWidth = 300;
  753. control.SetBinding(ComboBox.SelectedItemProperty, binding);
  754. control.PreviewMouseLeftButtonDown += ChuckControl_PreviewMouseLeftButtonDown;
  755. break;
  756. case "DechuckRecipe":
  757. //if (currentChamber != JetChamber.Venus)
  758. //{
  759. // continue;
  760. //}
  761. //string[] dechucklist = new string[] { "" };
  762. //ArrayList dearrayList = new ArrayList(dechucklist.ToList());
  763. //IEnumerable<string> delist = GetFilesNames(Path.Combine(QueryDataClient.Instance.Service.GetData("GetRTPath").ToString(), "Recipes", ModuleName)).ToList().Where(item => item.ToLower().Contains("dechuck"));
  764. //foreach (var i in delist)
  765. //{
  766. // dearrayList.Add(i);
  767. //}
  768. //dechucklist = (string[])dearrayList.ToArray(typeof(string));
  769. //StringBuilder destringBuilder = new StringBuilder();
  770. //for (int i = 0; i < dechucklist.Length; i++)
  771. //{
  772. // destringBuilder.Append(dechucklist[i] + "\t");
  773. //}
  774. control = new ComboBox()
  775. {
  776. ItemsSource = GetFilesNames(Path.Combine(QueryDataClient.Instance.Service.GetData("GetRTPath").ToString(), "Recipes", $"{ModuleName}\\DeChuck"))
  777. };
  778. //control.Height = 23;
  779. control.MinWidth = 100;
  780. control.MaxWidth = 300;
  781. control.SetBinding(ComboBox.SelectedItemProperty, binding);
  782. control.PreviewMouseLeftButtonDown += DechuckControl_PreviewMouseLeftButtonDown;
  783. break;
  784. case "IsShowTolerance":
  785. control = new CheckBox();
  786. control.SetBinding(CheckBox.IsCheckedProperty, binding);
  787. control.Style = null;
  788. control.VerticalAlignment = VerticalAlignment.Center;
  789. (control as CheckBox).Checked += RecipeViewModel_Checked;
  790. (control as CheckBox).Unchecked += RecipeViewModel_Checked;
  791. break;
  792. default:
  793. control = new TextBox();
  794. control.Margin = new Thickness(1, 0, 0, 0);
  795. control.BorderThickness = new Thickness(0, 0, 0, 1);
  796. control.BorderBrush = Brushes.White;
  797. control.FontSize = 15;
  798. control.Foreground = Brushes.Green;
  799. control.Background = Brushes.Transparent;
  800. control.VerticalAlignment = VerticalAlignment.Center;
  801. control.MinWidth = 15;
  802. control.SetBinding(TextBox.TextProperty, binding);
  803. object[] objAttrs = propertyInfo.GetCustomAttributes(typeof(IsOnlyReadAttribute), true);
  804. if (objAttrs.Length > 0)
  805. {
  806. (control as TextBox).IsReadOnly = true;
  807. }
  808. break;
  809. }
  810. control.Margin = new Thickness(20, 3, 0, 7);
  811. control.Width = 250;
  812. HeadWrapPanel.Children.Add(control);
  813. }
  814. }
  815. private void RecipeViewModel_Checked(object sender, RoutedEventArgs e)
  816. {
  817. LoadRecipe(CurrentRecipe);
  818. }
  819. private void ChuckControl_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
  820. {
  821. var items = GetFilesNames(Path.Combine(QueryDataClient.Instance.Service.GetData("GetRTPath").ToString(), "Recipes", $"{ModuleName}\\Chuck")).ToList();
  822. items.Add("");
  823. (sender as ComboBox).ItemsSource = items;
  824. }
  825. private void DechuckControl_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
  826. {
  827. var items = GetFilesNames(Path.Combine(QueryDataClient.Instance.Service.GetData("GetRTPath").ToString(), "Recipes", $"{ModuleName}\\DeChuck")).ToList();
  828. items.Add("");
  829. (sender as ComboBox).ItemsSource = items;
  830. }
  831. private void ChangeUI(object sender, SelectionChangedEventArgs e)
  832. {
  833. var t = sender as ComboBox;
  834. if (t.SelectedValue.ToString() != "Process")
  835. {
  836. headWrapPanel.Children[8].Visibility = Visibility.Collapsed;
  837. headWrapPanel.Children[9].Visibility = Visibility.Collapsed;
  838. headWrapPanel.Children[10].Visibility = Visibility.Collapsed;
  839. headWrapPanel.Children[11].Visibility = Visibility.Collapsed;
  840. }
  841. else
  842. {
  843. headWrapPanel.Children[8].Visibility = Visibility.Visible;
  844. headWrapPanel.Children[9].Visibility = Visibility.Visible;
  845. headWrapPanel.Children[10].Visibility = Visibility.Visible;
  846. headWrapPanel.Children[11].Visibility = Visibility.Visible;
  847. }
  848. }
  849. private void MenuItemLeftInsert_Click(object sender, RoutedEventArgs e)
  850. {
  851. var t = ((sender as MenuItem).Parent as ContextMenu).PlacementTarget as TextBox;
  852. int insertIndex = Convert.ToInt32(t.Text) - 1;
  853. RecipeStep recipeStep;
  854. if (copyIndex == -1)
  855. {
  856. recipeStep = new RecipeStep();
  857. recipeStep.LstUnit = RecipeUnity.GetAllUnits(currentChamber, CurrentRecipe.Header.Type);
  858. CurrentRecipe.Steps.Insert(insertIndex, recipeStep);
  859. }
  860. else
  861. {
  862. var t1 = JsonConvert.SerializeObject(CurrentRecipe);
  863. recipeStep = Recipe.Load(t1).Steps[copyIndex - 1];
  864. CurrentRecipe.Steps.Insert(insertIndex, recipeStep);
  865. }
  866. for (int i = 0; i < CurrentRecipe.Steps.Count; i++)
  867. {
  868. CurrentRecipe.Steps[i].StepNo = i + 1;
  869. }
  870. ColumnDefinition col1 = new ColumnDefinition();
  871. col1.Width = GridLength.Auto;
  872. rightGrid.ColumnDefinitions.Add(col1);
  873. for (int i = 0; i < rightGrid.Children.Count; i++)
  874. {
  875. if (Grid.GetColumn(rightGrid.Children[i]) >= insertIndex)
  876. {
  877. Grid.SetColumn(rightGrid.Children[i], Grid.GetColumn(rightGrid.Children[i]) + 1);
  878. }
  879. }
  880. RecipeStepToGridColumn(recipeStep, rightGrid, insertIndex);
  881. }
  882. private void MenuItemRightInsert_Click(object sender, RoutedEventArgs e)
  883. {
  884. var t = ((sender as MenuItem).Parent as ContextMenu).PlacementTarget as TextBox;
  885. int insertIndex = Convert.ToInt32(t.Text);
  886. RecipeStep recipeStep;
  887. if (copyIndex == -1)
  888. {
  889. recipeStep = new RecipeStep();
  890. recipeStep.LstUnit = RecipeUnity.GetAllUnits(currentChamber, CurrentRecipe.Header.Type);
  891. CurrentRecipe.Steps.Insert(insertIndex, recipeStep);
  892. }
  893. else
  894. {
  895. var t1 = JsonConvert.SerializeObject(CurrentRecipe);
  896. recipeStep = Recipe.Load(t1).Steps[copyIndex - 1];
  897. CurrentRecipe.Steps.Insert(insertIndex, recipeStep);
  898. }
  899. for (int i = 0; i < CurrentRecipe.Steps.Count; i++)
  900. {
  901. CurrentRecipe.Steps[i].StepNo = i + 1;
  902. }
  903. ColumnDefinition col1 = new ColumnDefinition();
  904. col1.Width = GridLength.Auto;
  905. rightGrid.ColumnDefinitions.Add(col1);
  906. for (int i = 0; i < rightGrid.Children.Count; i++)
  907. {
  908. if (Grid.GetColumn(rightGrid.Children[i]) >= insertIndex)
  909. {
  910. Grid.SetColumn(rightGrid.Children[i], Grid.GetColumn(rightGrid.Children[i]) + 1);
  911. }
  912. }
  913. RecipeStepToGridColumn(recipeStep, rightGrid, insertIndex);
  914. }
  915. private void MenuItemDelete_Click(object sender, RoutedEventArgs e)
  916. {
  917. var t = ((sender as MenuItem).Parent as ContextMenu).PlacementTarget as TextBox;
  918. int deleteIndex = Convert.ToInt32(t.Text) - 1;
  919. CurrentRecipe.Steps.RemoveAt(deleteIndex);
  920. for (int i = 0; i < CurrentRecipe.Steps.Count; i++)
  921. {
  922. CurrentRecipe.Steps[i].StepNo = i + 1;
  923. }
  924. RemoveColumnFromGrid(rightGrid, deleteIndex);
  925. rightGrid.ColumnDefinitions.RemoveAt(deleteIndex);
  926. for (int i = 0; i < rightGrid.Children.Count; i++)
  927. {
  928. if (Grid.GetColumn(rightGrid.Children[i]) >= deleteIndex)
  929. {
  930. Grid.SetColumn(rightGrid.Children[i], Grid.GetColumn(rightGrid.Children[i]) - 1);
  931. }
  932. }
  933. }
  934. private void MenuItemCopy_Click(object sender, RoutedEventArgs e)
  935. {
  936. var t = ((sender as MenuItem).Parent as ContextMenu).PlacementTarget as TextBox;
  937. copyIndex = Convert.ToInt32(t.Text);
  938. }
  939. #endregion
  940. #region 私有方法
  941. private void RecipeStepToGridColumn(RecipeStep recipeStep, Grid grid, int columnIndex)
  942. {
  943. Type recipeType = recipeStep.GetType();
  944. int rowIndex = 0;
  945. foreach (PropertyInfo propertyInfo in recipeType.GetProperties())
  946. {
  947. string propertyInfoName = propertyInfo.Name;
  948. string propertyTypeName = propertyInfo.PropertyType.Name;
  949. if (propertyInfoName != "LstUnit")
  950. {
  951. if ((propertyInfoName == "EPDConfig" || propertyInfoName == "MinEndPointTime" || propertyInfoName == "MaxEndPointTime" || propertyInfoName == "OverEtchPercent") && isInstalledEPD == false)
  952. {
  953. continue;
  954. }
  955. if (columnIndex == 0)
  956. {
  957. RowDefinition row1 = new RowDefinition();
  958. row1.Height = new GridLength(controlHeight);
  959. grid.RowDefinitions.Add(row1);
  960. }
  961. Binding binding = new Binding()
  962. {
  963. Source = recipeStep, // 数据源
  964. Path = new PropertyPath(propertyInfoName), // 需绑定的数据源属性名
  965. Mode = BindingMode.TwoWay, // 绑定模式
  966. UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged //触发器
  967. };
  968. switch (propertyTypeName)
  969. {
  970. case "Int32":
  971. case "String":
  972. case "Single":
  973. case "Double":
  974. if (propertyInfoName == "EPDConfig")
  975. {
  976. if (currentEPDType == EPDType.Socket)
  977. {
  978. ComboBox EPDcomboBox = new ComboBox();
  979. EPDcomboBox.Style = (Style)recipeView.FindResource("customeComboBoxStyle");
  980. EPDcomboBox.Background = new SolidColorBrush(Colors.Black);
  981. EPDcomboBox.SetBinding(ComboBox.SelectedItemProperty, binding);
  982. EPDcomboBox.ItemsSource = EPDCfgList;
  983. grid.Children.Add(EPDcomboBox);
  984. Grid.SetRow(EPDcomboBox, rowIndex);
  985. Grid.SetColumn(EPDcomboBox, columnIndex);
  986. }
  987. else if (currentEPDType == EPDType.WCF)
  988. {
  989. Button EPDButton = new Button();
  990. EPDButton.Content = "EndPoint";
  991. EPDButton.Cursor = Cursors.Hand;
  992. EPDButton.Tag = $"{CurrentRecipeName}.{(columnIndex).ToString()}";
  993. EPDButton.Style = null;
  994. EPDButton.Click += EPDButton_Click;
  995. grid.Children.Add(EPDButton);
  996. Grid.SetRow(EPDButton, rowIndex);
  997. Grid.SetColumn(EPDButton, columnIndex);
  998. }
  999. break;
  1000. }
  1001. TextBox textBox = new TextBox();
  1002. textBox.HorizontalContentAlignment = HorizontalAlignment.Center;
  1003. textBox.VerticalContentAlignment = VerticalAlignment.Center;
  1004. textBox.SetBinding(TextBox.TextProperty, binding);
  1005. grid.Children.Add(textBox);
  1006. Grid.SetRow(textBox, rowIndex);
  1007. Grid.SetColumn(textBox, columnIndex);
  1008. object[] objAttrs = propertyInfo.GetCustomAttributes(typeof(IsOnlyReadAttribute), true);
  1009. if (objAttrs.Length > 0)
  1010. {
  1011. textBox.IsReadOnly = true;
  1012. ContextMenu contextmenu = new ContextMenu();
  1013. textBox.ContextMenu = contextmenu;
  1014. MenuItem menuItemDelete = new MenuItem();
  1015. menuItemDelete.Header = "Delete";
  1016. menuItemDelete.Click += MenuItemDelete_Click;
  1017. MenuItem menuItemLeftInsert = new MenuItem();
  1018. menuItemLeftInsert.Header = "Left Insert";
  1019. menuItemLeftInsert.Click += MenuItemLeftInsert_Click;
  1020. MenuItem menuItemRightInsert = new MenuItem();
  1021. menuItemRightInsert.Header = "Right Insert";
  1022. menuItemRightInsert.Click += MenuItemRightInsert_Click;
  1023. MenuItem menuItemCopy = new MenuItem();
  1024. menuItemCopy.Tag = textBox.Text;
  1025. menuItemCopy.Header = "Copy";
  1026. menuItemCopy.Click += MenuItemCopy_Click;
  1027. contextmenu.Items.Add(menuItemCopy);
  1028. contextmenu.Items.Add(menuItemDelete);
  1029. contextmenu.Items.Add(menuItemLeftInsert);
  1030. contextmenu.Items.Add(menuItemRightInsert);
  1031. }
  1032. break;
  1033. case "Boolean":
  1034. CheckBox checkBox = new CheckBox();
  1035. checkBox.SetBinding(CheckBox.IsCheckedProperty, binding);
  1036. grid.Children.Add(checkBox);
  1037. Grid.SetRow(checkBox, rowIndex);
  1038. Grid.SetColumn(checkBox, columnIndex);
  1039. break;
  1040. default:
  1041. ComboBox comboBox = new ComboBox();
  1042. comboBox.Style = (Style)recipeView.FindResource("customeComboBoxStyle");
  1043. //comboBox.BorderThickness = new Thickness(1, 0, 1, 0);
  1044. comboBox.Background = new SolidColorBrush(Colors.Black);
  1045. comboBox.SetBinding(ComboBox.SelectedItemProperty, binding);
  1046. ItemsControlHelper.SetEnumValuesToItemsSource(comboBox, true);
  1047. grid.Children.Add(comboBox);
  1048. Grid.SetRow(comboBox, rowIndex);
  1049. Grid.SetColumn(comboBox, columnIndex);
  1050. break;
  1051. }
  1052. rowIndex++;
  1053. }
  1054. }
  1055. int unitIndex = 0;
  1056. foreach (var x in recipeStep.LstUnit.ToList())
  1057. {
  1058. Type unitType = x.GetType();
  1059. Binding checkbinding = null;
  1060. foreach (PropertyInfo propertyInfo in unitType.GetProperties())
  1061. {
  1062. object[] IgnoreAttrs = propertyInfo.GetCustomAttributes(typeof(IsCanConfigIgnore), true);
  1063. bool IsEnableRecipeExtension = Convert.ToBoolean(QueryDataClient.Instance.Service.GetConfig($"{ModuleName}.IsEnableRecipeExtension"));
  1064. if (IgnoreAttrs.Length > 0 && IsEnableRecipeExtension == false)
  1065. {
  1066. break;
  1067. }
  1068. object[] toleranceAttrs = propertyInfo.GetCustomAttributes(typeof(IsTolerance), true);
  1069. if (toleranceAttrs.Length > 0 && CurrentRecipe.Header.IsShowTolerance == false)
  1070. {
  1071. continue;
  1072. }
  1073. if (propertyInfo.Name == "UnitName")
  1074. {
  1075. continue;
  1076. }
  1077. //if (propertyInfo.Name.Contains("Gas"))
  1078. //{
  1079. // if (!(bool)QueryDataClient.Instance.Service.GetConfig($"{ModuleName}.MfcGas1.Enable"))
  1080. // {
  1081. // continue;
  1082. // }
  1083. //}
  1084. if (columnIndex == 0)
  1085. {
  1086. RowDefinition row1 = new RowDefinition();
  1087. row1.Height = new GridLength(controlHeight);
  1088. grid.RowDefinitions.Add(row1);
  1089. }
  1090. Binding binding = new Binding()
  1091. {
  1092. Source = recipeStep.LstUnit[unitIndex], // 数据源
  1093. //Path = new PropertyPath($"LstUnit[{k}]." + propertyInfo.Name), // 需绑定的数据源属性名
  1094. Path = new PropertyPath(propertyInfo.Name), // 需绑定的数据源属性名
  1095. Mode = BindingMode.TwoWay, // 绑定模式
  1096. UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged //触发器
  1097. };
  1098. var item = propertyInfo.PropertyType.Name;
  1099. switch (item)
  1100. {
  1101. case "Int32":
  1102. case "String":
  1103. case "Single":
  1104. case "Double":
  1105. TextBox textBox = new TextBox();
  1106. textBox.HorizontalContentAlignment = HorizontalAlignment.Center;
  1107. textBox.VerticalContentAlignment = VerticalAlignment.Center;
  1108. if (checkbinding == null)
  1109. {
  1110. textBox.IsEnabled = true;
  1111. }
  1112. else
  1113. {
  1114. textBox.SetBinding(TextBox.IsEnabledProperty, checkbinding);
  1115. }
  1116. textBox.SetBinding(TextBox.TextProperty, binding);
  1117. grid.Children.Add(textBox);
  1118. Grid.SetRow(textBox, rowIndex);
  1119. Grid.SetColumn(textBox, columnIndex);
  1120. //object[] objAttrs = propertyInfo.GetCustomAttributes(typeof(IsOnlyReadAttribute), true);
  1121. //if (objAttrs.Length > 0)
  1122. //{
  1123. // textBox.IsReadOnly = true;
  1124. //}
  1125. break;
  1126. case "Boolean":
  1127. CheckBox checkBox = new CheckBox();
  1128. if (checkbinding == null)
  1129. {
  1130. checkbinding = new Binding
  1131. {
  1132. Source = checkBox, // 数据源
  1133. Path = new PropertyPath("IsChecked"), // 需绑定的数据源属性名
  1134. Mode = BindingMode.TwoWay, // 绑定模式
  1135. UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged //触发器
  1136. };
  1137. }
  1138. checkBox.SetBinding(CheckBox.IsCheckedProperty, binding);
  1139. grid.Children.Add(checkBox);
  1140. Grid.SetRow(checkBox, rowIndex);
  1141. Grid.SetColumn(checkBox, columnIndex);
  1142. break;
  1143. default:
  1144. //if (checkbinding != null)
  1145. //{
  1146. // break;
  1147. //}
  1148. ComboBox comboBox = new ComboBox();
  1149. comboBox.BorderBrush = Brushes.Gray;
  1150. comboBox.Style = (Style)recipeView.FindResource("customeComboBoxStyle");
  1151. //comboBox.BorderThickness =new Thickness(1,0,1,0);
  1152. if (checkbinding == null)
  1153. {
  1154. comboBox.IsEnabled = true;
  1155. }
  1156. else
  1157. {
  1158. comboBox.SetBinding(TextBox.IsEnabledProperty, checkbinding);
  1159. }
  1160. comboBox.Background = Brushes.White;
  1161. string path = propertyInfo.Name;
  1162. comboBox.SetBinding(ComboBox.SelectedItemProperty, binding);
  1163. ItemsControlHelper.SetEnumValuesToItemsSource(comboBox, true);
  1164. grid.Children.Add(comboBox);
  1165. Grid.SetRow(comboBox, rowIndex);
  1166. Grid.SetColumn(comboBox, columnIndex);
  1167. break;
  1168. }
  1169. rowIndex++;
  1170. }
  1171. unitIndex++;
  1172. }
  1173. }
  1174. private void RecipeStepToGridColumnOnlyTitle(RecipeStep recipeStep, Grid grid)
  1175. {
  1176. Type recipeType = recipeStep.GetType();
  1177. int i = 0;
  1178. ColumnDefinition col1 = new ColumnDefinition();
  1179. grid.ColumnDefinitions.Add(col1);
  1180. foreach (PropertyInfo propertyInfo in recipeType.GetProperties())
  1181. {
  1182. string propertyInfoName = propertyInfo.Name;
  1183. string propertyTypeName = propertyInfo.PropertyType.Name;
  1184. if (propertyInfoName != "LstUnit")
  1185. {
  1186. if ((propertyInfoName == "EPDConfig" || propertyInfoName == "MinEndPointTime" || propertyInfoName == "MaxEndPointTime" || propertyInfoName == "OverEtchPercent") && isInstalledEPD == false)
  1187. {
  1188. continue;
  1189. }
  1190. RowDefinition row1 = new RowDefinition();
  1191. row1.Height = new GridLength(controlHeight);
  1192. grid.RowDefinitions.Add(row1);
  1193. TextBox textBlock = new TextBox();
  1194. textBlock.Padding = new Thickness(0, 3, 0, 0);
  1195. textBlock.IsReadOnly = true;
  1196. object[] NameAttrs = propertyInfo.GetCustomAttributes(typeof(CustomName), true);
  1197. string name;
  1198. if (NameAttrs.Length > 0)
  1199. {
  1200. name = (NameAttrs[0] as CustomName).Name;
  1201. }
  1202. else
  1203. {
  1204. name = propertyInfo.Name;
  1205. }
  1206. textBlock.Text = name;
  1207. //textBlock.FontSize = 15;
  1208. grid.Children.Add(textBlock);
  1209. textBlock.Background = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FAFAFA"));
  1210. Grid.SetRow(textBlock, i);
  1211. Grid.SetColumn(textBlock, 0);
  1212. i++;
  1213. }
  1214. }
  1215. foreach (var x in recipeStep.LstUnit.ToList())
  1216. {
  1217. Type unitType = x.GetType();
  1218. bool isUnitFirstRow = true;
  1219. foreach (PropertyInfo propertyInfo in unitType.GetProperties())
  1220. {
  1221. object[] IgnoreAttrs = propertyInfo.GetCustomAttributes(typeof(IsCanConfigIgnore), true);
  1222. bool IsEnableRecipeExtension = Convert.ToBoolean(QueryDataClient.Instance.Service.GetConfig($"{ModuleName}.IsEnableRecipeExtension"));
  1223. if (IgnoreAttrs.Length > 0 && IsEnableRecipeExtension == false)
  1224. {
  1225. break;
  1226. }
  1227. object[] toleranceAttrs = propertyInfo.GetCustomAttributes(typeof(IsTolerance), true);
  1228. if (toleranceAttrs.Length > 0 && CurrentRecipe.Header.IsShowTolerance == false)
  1229. {
  1230. continue;
  1231. }
  1232. if (propertyInfo.Name == "UnitName")
  1233. {
  1234. continue;
  1235. }
  1236. if (propertyInfo.Name.Contains("Gas"))
  1237. {
  1238. if (!(bool)QueryDataClient.Instance.Service.GetConfig($"{ModuleName}.MfcGas1.Enable"))
  1239. {
  1240. continue;
  1241. }
  1242. }
  1243. RowDefinition row1 = new RowDefinition();
  1244. row1.Height = new GridLength(controlHeight);
  1245. grid.RowDefinitions.Add(row1);
  1246. TextBox textBlock = new TextBox();
  1247. if (isUnitFirstRow)
  1248. {
  1249. textBlock.FontWeight = FontWeights.Bold;
  1250. textBlock.FontSize = 15;
  1251. isUnitFirstRow = false;
  1252. textBlock.Padding = new Thickness(0, 2, 0, 0);
  1253. }
  1254. else
  1255. {
  1256. textBlock.Padding = new Thickness(0, 3, 0, 0);
  1257. }
  1258. textBlock.IsReadOnly = true;
  1259. switch (propertyInfo.Name)
  1260. {
  1261. case "Gas1":
  1262. var data1 = (AITMfcData)QueryDataClient.Instance.Service.GetData($"{ModuleName}.MfcGas1");
  1263. textBlock.Text = $"{propertyInfo.Name}({data1.DisplayName},{data1.Scale})";
  1264. break;
  1265. case "Gas2":
  1266. var data2 = (AITMfcData)QueryDataClient.Instance.Service.GetData($"{ModuleName}.MfcGas2");
  1267. textBlock.Text = $"{propertyInfo.Name}({data2.DisplayName},{data2.Scale})";
  1268. break;
  1269. case "Gas3":
  1270. var data3 = (AITMfcData)QueryDataClient.Instance.Service.GetData($"{ModuleName}.MfcGas3");
  1271. textBlock.Text = $"{propertyInfo.Name}({data3.DisplayName},{data3.Scale})";
  1272. break;
  1273. case "Gas4":
  1274. var data4 = (AITMfcData)QueryDataClient.Instance.Service.GetData($"{ModuleName}.MfcGas4");
  1275. textBlock.Text = $"{propertyInfo.Name}({data4.DisplayName},{data4.Scale})";
  1276. break;
  1277. case "Gas5":
  1278. var data5 = (AITMfcData)QueryDataClient.Instance.Service.GetData($"{ModuleName}.MfcGas5");
  1279. textBlock.Text = $"{propertyInfo.Name}({data5.DisplayName},{data5.Scale})";
  1280. break;
  1281. case "Gas6":
  1282. var data6 = (AITMfcData)QueryDataClient.Instance.Service.GetData($"{ModuleName}.MfcGas6");
  1283. textBlock.Text = $"{propertyInfo.Name}({data6.DisplayName},{data6.Scale})";
  1284. break;
  1285. case "Gas7":
  1286. var data7 = (AITMfcData)QueryDataClient.Instance.Service.GetData($"{ModuleName}.MfcGas7");
  1287. textBlock.Text = $"{propertyInfo.Name}({data7.DisplayName},{data7.Scale})";
  1288. break;
  1289. case "Gas8":
  1290. var data8 = (AITMfcData)QueryDataClient.Instance.Service.GetData($"{ModuleName}.MfcGas8");
  1291. textBlock.Text = $"{propertyInfo.Name}({data8.DisplayName},{data8.Scale})";
  1292. break;
  1293. case "Gas9":
  1294. var data9 = (AITMfcData)QueryDataClient.Instance.Service.GetData($"{ModuleName}.MfcGas9");
  1295. textBlock.Text = $"{propertyInfo.Name}({data9.DisplayName},{data9.Scale})";
  1296. break;
  1297. case "Gas10":
  1298. var data10 = (AITMfcData)QueryDataClient.Instance.Service.GetData($"{ModuleName}.MfcGas10");
  1299. textBlock.Text = $"{propertyInfo.Name}({data10.DisplayName},{data10.Scale})";
  1300. break;
  1301. case "Gas11":
  1302. var data11 = (AITMfcData)QueryDataClient.Instance.Service.GetData($"{ModuleName}.MfcGas11");
  1303. textBlock.Text = $"{propertyInfo.Name}({data11.DisplayName},{data11.Scale})";
  1304. break;
  1305. case "Gas12":
  1306. var data12 = (AITMfcData)QueryDataClient.Instance.Service.GetData($"{ModuleName}.MfcGas12");
  1307. textBlock.Text = $"{propertyInfo.Name}({data12.DisplayName},{data12.Scale})";
  1308. break;
  1309. default:
  1310. object[] NameAttrs = propertyInfo.GetCustomAttributes(typeof(CustomName), true);
  1311. string name;
  1312. if (NameAttrs.Length > 0)
  1313. {
  1314. name = (NameAttrs[0] as CustomName).Name;
  1315. }
  1316. else
  1317. {
  1318. name = propertyInfo.Name;
  1319. }
  1320. textBlock.Text = name;
  1321. break;
  1322. }
  1323. grid.Children.Add(textBlock);
  1324. Grid.SetRow(textBlock, i);
  1325. Grid.SetColumn(textBlock, 0);
  1326. i++;
  1327. }
  1328. }
  1329. }
  1330. private void EPDButton_Click(object sender, RoutedEventArgs e)
  1331. {
  1332. Button button = sender as Button;
  1333. string para = button.Tag.ToString();
  1334. int stepno = Convert.ToInt32(para.Split('.')[1]) - 1;
  1335. var endpointconfigitem = new MECF.Framework.Common.CommonData.EndPointConfigItem();
  1336. if (CurrentRecipe.Steps[stepno].EPDConfig != null && CurrentRecipe.Steps[stepno].EPDConfig.Length > 20)
  1337. {
  1338. endpointconfigitem.SetValue(CurrentRecipe.Steps[stepno].EPDConfig);
  1339. }
  1340. (new EndPointDlg(para, endpointconfigitem, CurrentRecipe)).ShowDialog();
  1341. }
  1342. private void UpdateRecipeFileList()
  1343. {
  1344. XmlDocument doc = new XmlDocument();
  1345. doc.LoadXml(GetXmlRecipeList());
  1346. treeViewRcpList.Items.Clear();
  1347. CreateTreeViewItems(doc.DocumentElement, this.treeViewRcpList);
  1348. ExpandAllItems(this.treeViewRcpList);
  1349. }
  1350. private void LoadRecipe(Recipe recipe)
  1351. {
  1352. copyIndex = -1;
  1353. OnClearRecipe();
  1354. CurrentRecipe = recipe;
  1355. RecipeStepToGridColumnOnlyTitle(recipe.Steps[0], leftGrid);
  1356. for (int i = 0; i < recipe.Steps.Count; i++)
  1357. {
  1358. ColumnDefinition col1 = new ColumnDefinition();
  1359. col1.Width = GridLength.Auto;
  1360. rightGrid.ColumnDefinitions.Insert(i, col1);
  1361. RecipeStepToGridColumn(recipe.Steps[i], rightGrid, i);
  1362. }
  1363. string recipeContent = RecipeUnity.RecipeToString(CurrentRecipe);
  1364. SaveEAPRecipe(recipeContent, CurrentRecipe.Steps);
  1365. }
  1366. private void OnDeleteStep(int index)
  1367. {
  1368. if (CurrentRecipe != null && CurrentRecipe.Steps.Count > 1)
  1369. {
  1370. RemoveColumnFromGrid(rightGrid, index);
  1371. rightGrid.ColumnDefinitions.RemoveAt(index);
  1372. CurrentRecipe.Steps.RemoveAt(index);
  1373. }
  1374. }
  1375. /// <summary>
  1376. /// 删除Grid某列数据
  1377. /// </summary>
  1378. /// <param name="grid"></param>
  1379. /// <param name="column"></param>
  1380. public void RemoveColumnFromGrid(Grid grid, int column)
  1381. {
  1382. List<UIElement> listControl = new List<UIElement>();
  1383. for (int i = 0; i < grid.Children.Count; i++)
  1384. {
  1385. var child = grid.Children[i];
  1386. if (Grid.GetColumn(child) == column)
  1387. {
  1388. listControl.Add(child);
  1389. }
  1390. }
  1391. listControl.ForEach(x =>
  1392. {
  1393. grid.Children.Remove(x);
  1394. });
  1395. }
  1396. private void OnRefresh()
  1397. {
  1398. if (CurrentRecipeName != "")
  1399. {
  1400. string path = Path.Combine(QueryDataClient.Instance.Service.GetData("GetRTPath").ToString(), "Recipes", ModuleName, typeFolder, $"{CurrentRecipeName}.rcp");
  1401. string xmlRecipeData = m_uiRecipeManager.LoadRecipeByPath(path);
  1402. CurrentRecipe = Recipe.Load(xmlRecipeData);
  1403. LoadHeadWrapPanel(headWrapPanel, CurrentRecipe);
  1404. LoadRecipe(CurrentRecipe);
  1405. }
  1406. }
  1407. private void OnExpand()
  1408. {
  1409. HeadExpand = !HeadExpand;
  1410. if (HeadExpand)
  1411. {
  1412. recipeView.expandGrid.Width = 300;
  1413. }
  1414. else
  1415. {
  1416. recipeView.expandGrid.Width = 30;
  1417. }
  1418. }
  1419. private void OnUnload()
  1420. {
  1421. //if (CurrentRecipeName == null || CurrentRecipeName == "")
  1422. //{
  1423. // return;
  1424. //}
  1425. //if (WPFMessageBox.ShowQuestion($"Is Save Recipe {CurrentRecipeName}", "", false) == MessageBoxResult.Yes)
  1426. //{
  1427. // OnSaveRecipe();
  1428. //}
  1429. }
  1430. private void OnClearRecipe()
  1431. {
  1432. for (int i = 0; i < rightGrid.ColumnDefinitions.Count; i++)
  1433. {
  1434. rightGrid.ColumnDefinitions[i].Width = new GridLength(75);
  1435. }
  1436. leftGrid.Children.Clear();
  1437. rightGrid.Children.Clear();
  1438. leftGrid.ColumnDefinitions.Clear();
  1439. rightGrid.ColumnDefinitions.Clear();
  1440. rightGrid.RowDefinitions.Clear();
  1441. leftGrid.RowDefinitions.Clear();
  1442. GC.Collect(); // This should pick up the control removed at a previous MouseDown
  1443. GC.WaitForPendingFinalizers(); // Doesn't help either
  1444. //rightGrid.Visibility = Visibility.Visible;
  1445. }
  1446. private void ExpandAllItems(ItemsControl control)
  1447. {
  1448. if (control == null)
  1449. {
  1450. return;
  1451. }
  1452. foreach (Object item in control.Items)
  1453. {
  1454. System.Windows.Controls.TreeViewItem treeItem = control.ItemContainerGenerator.ContainerFromItem(item) as TreeViewItem;
  1455. if (treeItem == null || !treeItem.HasItems)
  1456. {
  1457. continue;
  1458. }
  1459. treeItem.IsExpanded = true;
  1460. ExpandAllItems(treeItem as ItemsControl);
  1461. }
  1462. }
  1463. private bool RecipeNameIsOk(string recipeName)
  1464. {
  1465. if (recipeName.Contains(' '))
  1466. {
  1467. WPFMessageBox.ShowError("Recipe Name 包含空格,不符合规格");
  1468. return false;
  1469. }
  1470. if (recipeName.Length > 25)
  1471. {
  1472. WPFMessageBox.ShowError("Recipe Name 大于25个字符,不符合规格");
  1473. return false;
  1474. }
  1475. return true;
  1476. }
  1477. #endregion
  1478. }
  1479. }