RecipeEditorControlViewModel.cs 105 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Collections.ObjectModel;
  4. using System.ComponentModel;
  5. using System.Diagnostics;
  6. using System.IO;
  7. using System.Linq;
  8. using System.Text.RegularExpressions;
  9. using System.Threading.Tasks;
  10. using System.Windows;
  11. using System.Windows.Controls;
  12. using System.Windows.Data;
  13. using System.Windows.Input;
  14. using System.Windows.Media;
  15. using System.Xml;
  16. using Aitex.UI.RecipeEditor.Core;
  17. using Aitex.UI.RecipeEditor.View;
  18. using ExcelLibrary.SpreadSheet;
  19. using Microsoft.Win32;
  20. using Xceed.Wpf.DataGrid;
  21. namespace Aitex.UI.RecipeEditor
  22. {
  23. public class RecipeEditorControlViewModel : INotifyPropertyChanged
  24. {
  25. public List<Tuple<string, string, ObservableCollection<RecipeRow>, Guid>> UndoList { get; set; }
  26. public List<Tuple<string, string, ObservableCollection<RecipeRow>, Guid>> RedoList { get; set; }
  27. public bool IsUndoEnabled { get { return UndoList != null && UndoList.Count > 0; } }
  28. public bool IsRedoEnabled { get { return RedoList != null && RedoList.Count > 0; } }
  29. public ObservableCollection<RecipeRow> RecipeRows { get; set; }
  30. private ObservableCollection<RecipeRow> _previousRecipeRows { get; set; }
  31. private string _valueBeforeEditing { get; set; }
  32. private string _currentRecipeVariationName = string.Empty;
  33. private SmartCellData _currentEditingCellData { get; set; }
  34. public List<Tuple<int/*row no*/, int/*col no*/, string/*var name*/, string/*reason*/>> Errors { get; set; }
  35. public List<Tuple<string, string>> CreateRecipeList { get; set; }
  36. public List<Tuple<string, string>> OpenRecipeList { get; set; }
  37. public DataGridControl DataGridControl { get; set; }
  38. public int CurrentRunningStepNo { get; set; }
  39. public Visibility SingleAppElementVisibility { get; set; }
  40. public Visibility RecipeInfoTextVisibility { get; set; }
  41. public ICommand ShowDetailedErrInfoCommand { get; set; }
  42. public ICommand EditRecipeInfoCommand { get; set; }
  43. //public ICommand CellContentChangedCommand { get; set; }
  44. public ICommand RightClickCommand { get; set; }
  45. public ICommand OpenLocalRecipeCommand { get; set; }
  46. public ICommand ExpandGroupCommand { get; set; }
  47. public ICommand CollapseGroupCommand { get; set; }
  48. public ICommand SaveRecipeCommand { get; set; }
  49. public ICommand RecipeHelpDocCommand { get; set; }
  50. public ICommand RecipeExport2ExcelCommand { get; set; }
  51. public ICommand ToggleHideSameCommand { get; set; }
  52. public ICommand UndoCommand { get; set; }
  53. public ICommand RedoCommand { get; set; }
  54. public ICommand SmartCellEditorLoadedCommand { get; set; }
  55. public ICommand SmartCellEditorUnloadedCommand { get; set; }
  56. public RecipeHead RecipeHead { get; set; }
  57. public bool IsBusy { get; set; }
  58. public bool IsHideSameContent { get; set; }
  59. public string RecipeInfo { get; set; }
  60. public HashSet<string> MaskedTechNames { get; set; }
  61. public HashSet<string> MaskedCatalogNames { get; set; }
  62. public event EventHandler OnSaveRecipeFile;
  63. public event EventHandler OnLocalRecipeOpened;
  64. public event EventHandler OnLoadRecipeContent;
  65. public bool IsRecipeModified { get; set; }
  66. public string UserName { set; get; }
  67. //private List<Tuple<string, string, string>> SourceDilteInjectRestrictions { get; set; }
  68. private Dictionary<string, string> _preDefinedRecipeVars { get; set; }
  69. private List<Tuple<string/*varName*/, string/*check condition*/, string/*message*/>> _validationRules { get; set; }
  70. private List<string> _checkVariables { get; set; }
  71. private Dictionary<string, int> RowVarNameDic { get; set; }
  72. private Dictionary<int, List<SmartCellData>> _copiedColumnDatas = new Dictionary<int, List<SmartCellData>>();
  73. private Dictionary<string/*CatalogName*/, Dictionary<string/*GroupName*/, List<RecipeVariableDefine/*StepList*/>>> _recipeReadingFormat;
  74. private Dictionary<string/*ModuleName*/, List<string>/*each item's control name*/> _recipeSavingFormat;
  75. private string _currentRecipeFormatContent;
  76. public bool IsBarcodeEnabled
  77. {
  78. get; set;
  79. }
  80. public Visibility IsBarcodeVisibility
  81. {
  82. get
  83. {
  84. return IsBarcodeEnabled ? Visibility.Visible : Visibility.Hidden;
  85. }
  86. }
  87. /// <summary>
  88. /// class construction
  89. /// </summary>
  90. public RecipeEditorControlViewModel()
  91. {
  92. UndoList = new List<Tuple<string, string, ObservableCollection<RecipeRow>, Guid>>();
  93. RedoList = new List<Tuple<string, string, ObservableCollection<RecipeRow>, Guid>>();
  94. //if(SingleAppElementVisibility
  95. CreateRecipeList = new List<Tuple<string, string>>();
  96. OpenRecipeList = new List<Tuple<string, string>>();
  97. foreach (var item in GetDefinedRecipeVariations())
  98. {
  99. CreateRecipeList.Add(new Tuple<string, string>("配置:" + item, item));
  100. OpenRecipeList.Add(new Tuple<string, string>("转换为配置:" + item, item));
  101. }
  102. RecipeInfoTextVisibility = Visibility.Collapsed;
  103. SingleAppElementVisibility = Visibility.Collapsed;
  104. RightClickCommand = new DelegatedCommand((o) => true, (o) => RightClickAction());
  105. ExpandGroupCommand = new DelegatedCommand((o) => true, (o) => ExpandGroups());
  106. CollapseGroupCommand = new DelegatedCommand((o) => true, (o) => CollapseGroups());
  107. SaveRecipeCommand = new DelegatedCommand((o) => true, (o) => SaveRecipeFile());
  108. OpenLocalRecipeCommand = new DelegatedCommand((o) => true, (o) => OpenLocalRecipe());
  109. ShowDetailedErrInfoCommand = new DelegatedCommand((o) => true, (o) => ShowDetailedErrInformation());
  110. EditRecipeInfoCommand = new DelegatedCommand((o) => true, (o) => EditRecipeInformation());
  111. RecipeHelpDocCommand = new DelegatedCommand((o) => true, (o) => ShowHelpDocView());
  112. RecipeExport2ExcelCommand = new DelegatedCommand((o) => true, (o) => Export2Excel());
  113. ToggleHideSameCommand = new DelegatedCommand((o) => true, (o) => ToggleHideSameContent());
  114. UndoCommand = new DelegatedCommand((o) => true, (o) => UndoOperation(o));
  115. RedoCommand = new DelegatedCommand((o) => true, (o) => RedoOperation(o));
  116. SmartCellEditorLoadedCommand = new DelegatedCommand((o) => true, (o) => SmartCellEditorLoaded(o));
  117. SmartCellEditorUnloadedCommand = new DelegatedCommand((o) => true, (o) => SmartCellEditorUnloaded(o));
  118. }
  119. /// <summary>
  120. /// When smart cell editor loaded
  121. /// </summary>
  122. /// <param name="obj"></param>
  123. private void SmartCellEditorLoaded(object obj)
  124. {
  125. _currentEditingCellData = obj as SmartCellData;
  126. if (_currentEditingCellData == null) return;
  127. _valueBeforeEditing = _currentEditingCellData.Value;
  128. _previousRecipeRows = CloneRecipeRowData(RecipeRows);
  129. }
  130. /// <summary>
  131. /// make a clone of current recipe row data
  132. /// </summary>
  133. /// <returns></returns>
  134. private ObservableCollection<RecipeRow> CloneRecipeRowData(ObservableCollection<RecipeRow> oldData)
  135. {
  136. ObservableCollection<RecipeRow> newRecipeRows = new ObservableCollection<RecipeRow>();
  137. foreach (var item in oldData)
  138. {
  139. var newRecipeRow = new RecipeRow() { CatalogName = item.CatalogName, FriendlyName = item.FriendlyName, TechnicalName = item.TechnicalName, RecipeItems = new ObservableCollection<SmartCellData>() };
  140. newRecipeRows.Add(newRecipeRow);
  141. foreach (var item2 in item.RecipeItems)
  142. {
  143. var newRecipeItem = new SmartCellData() { Background = item2.Background, ErrInfo = item2.ErrInfo, FontWeight = item2.FontWeight, Foreground = item2.Foreground, IsHidden = item2.IsHidden, IsMasked = item2.IsMasked, IsRunning = item2.IsRunning, RecipeVariableDefine = item2.RecipeVariableDefine, Value = item2.Value };
  144. newRecipeRow.RecipeItems.Add(newRecipeItem);
  145. }
  146. }
  147. return newRecipeRows;
  148. }
  149. /// <summary>
  150. /// When smart cell editor unloaded
  151. /// </summary>
  152. /// <param name="obj"></param>
  153. private void SmartCellEditorUnloaded(object obj)
  154. {
  155. if (_currentEditingCellData != null && _currentEditingCellData.Value != _valueBeforeEditing)
  156. {
  157. IsRecipeModified = true;
  158. var ret = OverrideSelectedCellsData();
  159. if (ret < 2)
  160. AddUndoHistory(string.Format("第{0}步({1})",
  161. _currentEditingCellData.ColIndex + 1,
  162. _currentEditingCellData.RecipeVariableDefine.CatalogName + _currentEditingCellData.RecipeVariableDefine.FriendlyName), _previousRecipeRows);
  163. else
  164. AddUndoHistory(string.Format("第{0}步({1})等{2}个单元格数据",
  165. _currentEditingCellData.ColIndex + 1,
  166. _currentEditingCellData.RecipeVariableDefine.CatalogName + _currentEditingCellData.RecipeVariableDefine.FriendlyName, ret), _previousRecipeRows);
  167. }
  168. RefreshCellsDisplay(false);
  169. }
  170. /// <summary>
  171. /// Adding undo history
  172. /// </summary>
  173. /// <param name="description"></param>
  174. /// <param name="recipeRows"></param>
  175. private void AddUndoHistory(string description, ObservableCollection<RecipeRow> recipeRows)
  176. {
  177. System.Diagnostics.Debug.WriteLine(description);
  178. if (recipeRows == null)
  179. return;
  180. string shortDesc = "";
  181. if (description.Length > 50)
  182. {
  183. shortDesc = description.Substring(0, 50);
  184. shortDesc += "...";
  185. }
  186. else
  187. {
  188. shortDesc = description;
  189. }
  190. UndoList.Insert(0, new Tuple<string, string, ObservableCollection<RecipeRow>, Guid>(shortDesc, description, recipeRows, Guid.NewGuid()));
  191. UndoList = new List<Tuple<string, string, ObservableCollection<RecipeRow>, Guid>>(UndoList.ToList());
  192. RedoList = new List<Tuple<string, string, ObservableCollection<RecipeRow>, Guid>>();
  193. InvokePropertyChanged("UndoList");
  194. InvokePropertyChanged("RedoList");
  195. InvokePropertyChanged("IsUndoEnabled");
  196. InvokePropertyChanged("IsRedoEnabled");
  197. }
  198. /// <summary>
  199. /// Redo something here
  200. /// </summary>
  201. private void RedoOperation(object obj)
  202. {
  203. try
  204. {
  205. if (RedoList == null || RedoList.Count == 0)
  206. return;
  207. Guid redoId = Guid.Empty;
  208. if (obj == null)
  209. redoId = RedoList[0].Item4;
  210. else
  211. redoId = (Guid)obj;
  212. var itemIndex = RedoList.FindIndex((o) => o.Item4 == redoId);
  213. if (itemIndex < 0)
  214. return;
  215. UndoList.Reverse();
  216. for (int i = 0; i <= itemIndex; i++)
  217. {
  218. if (i == 0)
  219. UndoList.Add(new Tuple<string, string, ObservableCollection<RecipeRow>, Guid>(RedoList[i].Item1, RedoList[i].Item2, CloneRecipeRowData(RecipeRows), RedoList[i].Item4));
  220. else
  221. UndoList.Add(new Tuple<string, string, ObservableCollection<RecipeRow>, Guid>(RedoList[i].Item1, RedoList[i].Item2, RedoList[i - 1].Item3, RedoList[i].Item4));
  222. }
  223. UndoList.Reverse();
  224. UndoList = new List<Tuple<string, string, ObservableCollection<RecipeRow>, Guid>>(UndoList.ToList());
  225. RecipeRows = RedoList[itemIndex].Item3;
  226. RedoList.RemoveRange(0, itemIndex + 1);
  227. RedoList = new List<Tuple<string, string, ObservableCollection<RecipeRow>, Guid>>(RedoList.ToList());
  228. RefreshDataGrid();
  229. RefreshCellsDisplay(false);
  230. InvokePropertyChanged("UndoList");
  231. InvokePropertyChanged("RedoList");
  232. InvokePropertyChanged("IsUndoEnabled");
  233. InvokePropertyChanged("IsRedoEnabled");
  234. }
  235. catch (Exception ex)
  236. {
  237. System.Diagnostics.Debug.WriteLine(ex.Message);
  238. MessageBox.Show("恢复动作失败!\r\n\r\n" + ex.Message, "警告", MessageBoxButton.OK, MessageBoxImage.Warning);
  239. }
  240. }
  241. /// <summary>
  242. /// Undo something here
  243. /// </summary>
  244. private void UndoOperation(object obj)
  245. {
  246. try
  247. {
  248. if (UndoList == null || UndoList.Count == 0)
  249. return;
  250. Guid undoId = Guid.Empty;
  251. if (obj == null)
  252. undoId = UndoList[0].Item4;
  253. else
  254. undoId = (Guid)obj;
  255. var itemIndex = UndoList.FindIndex((o) => o.Item4 == undoId);
  256. if (itemIndex < 0)
  257. return;
  258. RedoList.Reverse();
  259. for (int i = 0; i <= itemIndex; i++)
  260. {
  261. if (i == 0)
  262. RedoList.Add(new Tuple<string, string, ObservableCollection<RecipeRow>, Guid>(UndoList[i].Item1, UndoList[i].Item2, CloneRecipeRowData(RecipeRows), UndoList[i].Item4));
  263. else
  264. RedoList.Add(new Tuple<string, string, ObservableCollection<RecipeRow>, Guid>(UndoList[i].Item1, UndoList[i].Item2, UndoList[i - 1].Item3, UndoList[i].Item4));
  265. }
  266. RedoList.Reverse();
  267. RedoList = new List<Tuple<string, string, ObservableCollection<RecipeRow>, Guid>>(RedoList.ToList());
  268. RecipeRows = UndoList[itemIndex].Item3;
  269. UndoList.RemoveRange(0, itemIndex + 1);
  270. UndoList = new List<Tuple<string, string, ObservableCollection<RecipeRow>, Guid>>(UndoList.ToList());
  271. RefreshDataGrid();
  272. RefreshCellsDisplay(false);
  273. InvokePropertyChanged("UndoList");
  274. InvokePropertyChanged("RedoList");
  275. InvokePropertyChanged("IsUndoEnabled");
  276. InvokePropertyChanged("IsRedoEnabled");
  277. }
  278. catch (Exception ex)
  279. {
  280. System.Diagnostics.Debug.WriteLine(ex.Message);
  281. MessageBox.Show("撤销动作失败!\r\n\r\n" + ex.Message, "警告", MessageBoxButton.OK, MessageBoxImage.Warning);
  282. }
  283. }
  284. /// <summary>
  285. /// hide or show same content before and after one step
  286. /// </summary>
  287. private void ToggleHideSameContent()
  288. {
  289. IsHideSameContent = !IsHideSameContent;
  290. RefreshCellsDisplay(false);
  291. }
  292. /// <summary>
  293. /// get recipe variations
  294. /// </summary>
  295. /// <returns></returns>
  296. public List<string> GetDefinedRecipeVariations()
  297. {
  298. var list1 = new List<string>();
  299. var dir = new System.IO.FileInfo(Process.GetCurrentProcess().MainModule.FileName).Directory;
  300. string cfgPath = dir + "\\Config\\";
  301. var di = new System.IO.DirectoryInfo(cfgPath);
  302. if (di.Exists)
  303. {
  304. foreach (var item in di.GetFiles("*.xml"))
  305. {
  306. list1.Add(item.Name.Substring(0, item.Name.Length - item.Extension.Length));
  307. }
  308. }
  309. return list1;
  310. }
  311. /// <summary>
  312. /// Export to excel
  313. /// </summary>
  314. private void Export2Excel()
  315. {
  316. try
  317. {
  318. if (RecipeRows == null) return;
  319. var dlg = new SaveFileDialog();
  320. dlg.DefaultExt = ".xls";
  321. dlg.Filter = "Excel文件 (.xls)|*.xls|所有文件 (*.*)|*.*";
  322. if (dlg.ShowDialog() == true)
  323. {
  324. if (File.Exists(dlg.FileName))
  325. File.Delete(dlg.FileName);
  326. Workbook workbook = new Workbook();
  327. Worksheet worksheet = new Worksheet("First Sheet");
  328. XmlDocument doc = new XmlDocument();
  329. doc.LoadXml(_currentRecipeFormatContent);
  330. var catalogNodes = doc.SelectNodes("TableRecipeFormat/Catalog");
  331. int groupRowIndex = 0;
  332. int stepRowIndex = 0;
  333. int catalogRowIndex = 0;
  334. foreach (XmlElement cNode in catalogNodes)
  335. {
  336. XmlNodeList sNodes = cNode.SelectNodes("Group/Step");
  337. string catalogHeader = cNode.Attributes["DisplayName"].Value;
  338. worksheet.Cells[catalogRowIndex, 0] = new ExcelLibrary.SpreadSheet.Cell(catalogHeader);
  339. catalogRowIndex += sNodes.Count;
  340. XmlNodeList gNodes = cNode.SelectNodes("Group");
  341. foreach (XmlElement gNode in gNodes)
  342. {
  343. XmlNodeList stepNodes = gNode.SelectNodes("Step");
  344. string groupHeader = gNode.Attributes["DisplayName"].Value;
  345. worksheet.Cells[groupRowIndex, 1] = new ExcelLibrary.SpreadSheet.Cell(groupHeader);
  346. groupRowIndex += stepNodes.Count;
  347. foreach (XmlElement nd in stepNodes)
  348. {
  349. string stepHeader = nd.Attributes["DisplayName"].Value;
  350. worksheet.Cells[stepRowIndex, 2] = new ExcelLibrary.SpreadSheet.Cell(stepHeader);
  351. stepRowIndex++;
  352. }
  353. }
  354. }
  355. string recipeContent = GetRecipeContentString();
  356. XmlDocument rcp = new XmlDocument();
  357. rcp.LoadXml(recipeContent);
  358. XmlNodeList stepNodeList = rcp.SelectNodes("/TableRecipeData/Step");
  359. for (int stepNo = 0; stepNo < stepNodeList.Count; stepNo++)
  360. {
  361. var dataDic = new Dictionary<string, string>();
  362. foreach (XmlAttribute att in (stepNodeList[stepNo] as XmlElement).Attributes)
  363. {
  364. dataDic.Add(att.Name, att.Value);
  365. }
  366. //fill sub node's attributes
  367. foreach (XmlElement subStep in stepNodeList[stepNo].ChildNodes)
  368. {
  369. foreach (XmlAttribute att in subStep.Attributes)
  370. {
  371. dataDic.Add(att.Name, att.Value);
  372. }
  373. foreach (XmlElement subsubStep in subStep.ChildNodes)
  374. {
  375. foreach (XmlAttribute att2 in subsubStep.Attributes)
  376. {
  377. dataDic.Add(att2.Name, att2.Value);
  378. }
  379. }
  380. }
  381. long length = dataDic.LongCount();
  382. int step = 0;
  383. foreach (string key in dataDic.Keys)
  384. {
  385. worksheet.Cells.ColumnWidth[(ushort)step] = 4000;
  386. var cellContent = dataDic[key];
  387. double v;
  388. if (double.TryParse(cellContent, out v))
  389. {
  390. worksheet.Cells[step, stepNo + 3] = new ExcelLibrary.SpreadSheet.Cell(v);
  391. }
  392. else
  393. {
  394. worksheet.Cells[step, stepNo + 3] = new ExcelLibrary.SpreadSheet.Cell(cellContent);
  395. }
  396. step++;
  397. }
  398. }
  399. workbook.Worksheets.Add(worksheet);
  400. workbook.Save(dlg.FileName);
  401. MessageBox.Show(string.Format("成功导出到Excel文件!\r\n\r\n{0}", dlg.FileName), "导出", MessageBoxButton.OK, MessageBoxImage.Information);
  402. }
  403. }
  404. catch (Exception ex)
  405. {
  406. System.Diagnostics.Debug.WriteLine(ex.Message);
  407. MessageBox.Show("导出Excel文件发生异常!\r\n\r\n" + ex.Message, "导出", MessageBoxButton.OK, MessageBoxImage.Error);
  408. }
  409. }
  410. /// <summary>
  411. /// Show recipe information
  412. /// </summary>
  413. private void ShowHelpDocView()
  414. {
  415. var view = RecipeHelpView.Instance;
  416. view.Owner = Application.Current.MainWindow;
  417. view.DataContext = this;
  418. if (view.Visibility == Visibility.Visible)
  419. view.Hide();
  420. else
  421. view.Show();
  422. }
  423. /// <summary>
  424. /// Edit recipe information
  425. /// </summary>
  426. private void EditRecipeInformation()
  427. {
  428. RecipeInfoEditor editor = new RecipeInfoEditor() { RecipeHead = this.RecipeHead, Owner = Application.Current.MainWindow };
  429. editor.ShowDialog();
  430. InvokePropertyChanged("RecipeHead");
  431. }
  432. public void EnableBarcode(bool enable)
  433. {
  434. IsBarcodeEnabled = enable;
  435. InvokePropertyChanged("IsBarcodeVisibility");
  436. }
  437. public void SetCurrentUser(string user)
  438. {
  439. UserName = user;
  440. InvokePropertyChanged("UserName");
  441. }
  442. /// <summary>
  443. /// Show recipe information
  444. /// </summary>
  445. private void ShowDetailedErrInformation()
  446. {
  447. var view = ErrorInformationDetailsView.Instance;
  448. view.Owner = Application.Current.MainWindow;
  449. view.DataContext = this;
  450. if (view.Visibility == Visibility.Visible)
  451. view.Hide();
  452. else
  453. view.Show();
  454. }
  455. /// <summary>
  456. /// Update selected cells data
  457. /// </summary>
  458. /// <returns>overrided cells number</returns>
  459. private int OverrideSelectedCellsData()
  460. {
  461. int overridedCellsNum = 0;
  462. if (_currentEditingCellData != null)
  463. {
  464. var finalCellData = _currentEditingCellData;
  465. bool containsEditingCell = false;
  466. foreach (var item in DataGridControl.SelectedCellRanges)
  467. {
  468. int startColIndex = Math.Min(item.ColumnRange.StartIndex, item.ColumnRange.EndIndex);
  469. int endColIndex = Math.Max(item.ColumnRange.StartIndex, item.ColumnRange.EndIndex);
  470. int startRowIndex = Math.Min(item.ItemRange.StartIndex, item.ItemRange.EndIndex);
  471. int endRowIndex = Math.Max(item.ItemRange.StartIndex, item.ItemRange.EndIndex);
  472. if (startColIndex > 0 && startColIndex <= RecipeRows[0].RecipeItems.Count &&
  473. endColIndex > 0 && endColIndex <= RecipeRows[0].RecipeItems.Count &&
  474. startRowIndex >= 0 && startRowIndex < RecipeRows.Count &&
  475. endRowIndex >= 0 && endRowIndex < RecipeRows.Count)
  476. {
  477. for (int m = startRowIndex; m <= endRowIndex; m++)
  478. {
  479. for (int n = startColIndex; n <= endColIndex; n++)
  480. {
  481. int rowIndex = m;
  482. int colIndex = n - 1;
  483. if (RecipeRows[rowIndex].RecipeItems[colIndex] == _currentEditingCellData)
  484. {
  485. containsEditingCell = true;
  486. break;
  487. }
  488. }
  489. }
  490. }
  491. }
  492. if (containsEditingCell)
  493. {
  494. foreach (var item in DataGridControl.SelectedCellRanges)
  495. {
  496. int startColIndex = Math.Min(item.ColumnRange.StartIndex, item.ColumnRange.EndIndex);
  497. int endColIndex = Math.Max(item.ColumnRange.StartIndex, item.ColumnRange.EndIndex);
  498. int startRowIndex = Math.Min(item.ItemRange.StartIndex, item.ItemRange.EndIndex);
  499. int endRowIndex = Math.Max(item.ItemRange.StartIndex, item.ItemRange.EndIndex);
  500. if (startColIndex > 0 && startColIndex <= RecipeRows[0].RecipeItems.Count &&
  501. endColIndex > 0 && endColIndex <= RecipeRows[0].RecipeItems.Count &&
  502. startRowIndex >= 0 && startRowIndex < RecipeRows.Count &&
  503. endRowIndex >= 0 && endRowIndex < RecipeRows.Count)
  504. {
  505. for (int m = startRowIndex; m <= endRowIndex; m++)
  506. {
  507. for (int n = startColIndex; n <= endColIndex; n++)
  508. {
  509. int rowIndex = m;
  510. int colIndex = n - 1;
  511. if (RecipeRows[rowIndex].RecipeItems[colIndex].RecipeVariableDefine.CellType == finalCellData.RecipeVariableDefine.CellType)
  512. {
  513. overridedCellsNum++;
  514. RecipeRows[rowIndex].RecipeItems[colIndex].Value = finalCellData.Value;
  515. RecipeRows[rowIndex].RecipeItems[colIndex].InvokePropertyChanged();
  516. }
  517. }
  518. }
  519. }
  520. }
  521. }
  522. }
  523. return overridedCellsNum;
  524. }
  525. /// <summary>
  526. /// Open local recipe operation
  527. /// </summary>
  528. /// <param name="recipeDefineFilePath"></param>
  529. public void OpenLocalRecipe(string recipeVariationName = "")
  530. {
  531. var dlg = new OpenFileDialog();
  532. dlg.DefaultExt = ".rcp";
  533. dlg.Filter = "Recipe File (.rcp)|*.rcp|All (*.*)|*.*";
  534. if (dlg.ShowDialog() == true)
  535. {
  536. try
  537. {
  538. XmlDocument rcpDoc = new XmlDocument();
  539. rcpDoc.Load(dlg.FileName);
  540. string recipeVariation = recipeVariationName;
  541. if (string.IsNullOrEmpty(recipeVariation))
  542. {
  543. var root = rcpDoc.SelectSingleNode("/TableRecipeData") as XmlElement;
  544. recipeVariation = root.Attributes["RecipeVersion"].Value;
  545. }
  546. var startupPath = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
  547. string dir = System.IO.Path.GetDirectoryName(startupPath);
  548. List<Aitex.Controls.RecipeCompare.Item> map = CustomXmlSerializer.Deserialize<List<Aitex.Controls.RecipeCompare.Item>>(new System.IO.FileInfo(System.IO.Path.Combine(dir, "map.xml")));
  549. Func<Aitex.Controls.RecipeCompare.Item, bool> predicate = item => item.Name.Equals(recipeVariation);
  550. System.IO.FileInfo fi = new System.IO.FileInfo(string.Format("{0}\\config\\{1}.xml", dir, map.Any(predicate) ? map.Single(predicate).No : recipeVariation));
  551. if (fi.Exists)
  552. {
  553. XmlDocument doc = new XmlDocument();
  554. doc.Load(fi.FullName);
  555. string formatXml = doc.SelectSingleNode("/Aitex/TableRecipeFormat").OuterXml;
  556. string recipeXml = rcpDoc.SelectSingleNode("/TableRecipeData").OuterXml;
  557. LoadRecipe(formatXml, recipeXml);
  558. if (OnLocalRecipeOpened != null)
  559. OnLocalRecipeOpened.Invoke(new Tuple<string, string>(recipeVariation, dlg.FileName), null);
  560. }
  561. else
  562. {
  563. MessageBox.Show(string.Format("工艺程序版本{0}的描述文件不存在,无法正确识别该版本的工艺程序文件。", recipeVariation), "工艺程序打开失败",
  564. MessageBoxButton.OK, MessageBoxImage.Error);
  565. }
  566. }
  567. catch (Exception ex)
  568. {
  569. System.Diagnostics.Debug.WriteLine(ex.Message);
  570. MessageBox.Show(string.Format("open recipe {0} failed,please confirm the recipe file is exist and valid。\r\n{1}", dlg.FileName, ex.Message), "Open recipe failed",
  571. MessageBoxButton.OK, MessageBoxImage.Error);
  572. }
  573. }
  574. }
  575. /// <summary>
  576. /// Save recipe file
  577. /// </summary>
  578. private void SaveRecipeFile()
  579. {
  580. try
  581. {
  582. if (Errors != null && Errors.Count > 0)
  583. {
  584. var ret = MessageBox.Show(string.Format("Recipe have {0} error,continue save?", Errors.Count), "Save", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
  585. if (ret != MessageBoxResult.Yes)
  586. return;
  587. }
  588. if (OnSaveRecipeFile != null)
  589. {
  590. IsRecipeModified = false;
  591. OnSaveRecipeFile.Invoke(GetRecipeContentString(), null);
  592. }
  593. }
  594. catch (Exception ex)
  595. {
  596. System.Diagnostics.Debug.WriteLine(ex.Message);
  597. MessageBox.Show("save recipe failed!\r\n\r\n" + ex.Message, "Save", MessageBoxButton.OK, MessageBoxImage.Warning);
  598. }
  599. }
  600. /// <summary>
  601. /// get string typed recipe content
  602. /// </summary>
  603. /// <returns></returns>
  604. public string GetRecipeContentString()
  605. {
  606. if (string.IsNullOrEmpty(UserName))
  607. {
  608. var dlg1 = new Aitex.UI.RecipeEditor.UserNameInput() { Owner = Application.Current.MainWindow };
  609. var ret = dlg1.ShowDialog();
  610. if (ret.HasValue && ret.Value)
  611. {
  612. UserName = dlg1.UserName;
  613. }
  614. }
  615. RecipeHead.LastRevisionTime = DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss");
  616. RecipeHead.LastModifiedBy = UserName;
  617. InvokePropertyChanged("RecipeHead");
  618. if (RecipeRows == null || RecipeRows.Count == 0 || RecipeRows[0].RecipeItems == null || RecipeRows[0].RecipeItems.Count == 0)
  619. return string.Empty;
  620. //Dictionary<string/*CatalogName*/, Dictionary<string/*GroupName*/, List<RecipeVariableDefine/*StepList*/>>> _recipeReadingFormat;
  621. XmlDocument doc = new XmlDocument();
  622. var rootNode = doc.CreateElement("TableRecipeData");
  623. rootNode.SetAttribute("RecipeVersion", RecipeHead.RecipeVariation);
  624. rootNode.SetAttribute("CreatedBy", RecipeHead.CreatedBy);
  625. rootNode.SetAttribute("CreationTime", RecipeHead.CreationTime);
  626. rootNode.SetAttribute("LastRevisedBy", RecipeHead.LastModifiedBy);
  627. rootNode.SetAttribute("LastRevisionTime", RecipeHead.LastRevisionTime);
  628. if (!string.IsNullOrEmpty(RecipeHead.PressureMode))
  629. {
  630. rootNode.SetAttribute("PressureMode", RecipeHead.PressureMode);
  631. }
  632. if (!string.IsNullOrEmpty(RecipeHead.BasePressure))
  633. {
  634. rootNode.SetAttribute("BasePressure", RecipeHead.BasePressure);
  635. }
  636. if (!string.IsNullOrEmpty(RecipeHead.ElectrodeTemp))
  637. {
  638. rootNode.SetAttribute("ElectrodeTemp", RecipeHead.ElectrodeTemp);
  639. }
  640. if (!string.IsNullOrEmpty(RecipeHead.PumpDownLimit))
  641. {
  642. rootNode.SetAttribute("PumpDownLimit", RecipeHead.PumpDownLimit);
  643. }
  644. if (!string.IsNullOrEmpty(RecipeHead.PurgeActive))
  645. {
  646. rootNode.SetAttribute("PurgeActive", RecipeHead.PurgeActive);
  647. }
  648. rootNode.SetAttribute("Barcode", RecipeHead.Barcode);
  649. rootNode.SetAttribute("Description", RecipeHead.Description);
  650. doc.AppendChild(rootNode);
  651. for (int stepIndex/* 0-> */ = 0; stepIndex < RecipeRows[0].RecipeItems.Count; stepIndex++)
  652. {
  653. var stepNode = doc.CreateElement("Step");
  654. rootNode.AppendChild(stepNode);
  655. foreach (var module in _recipeSavingFormat)
  656. {
  657. var moduleName = module.Key;
  658. XmlElement subNode = stepNode;
  659. if (!string.IsNullOrEmpty(moduleName))
  660. {
  661. string[] pathArr = moduleName.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
  662. for (int i = 0; i < pathArr.Length; i++)
  663. {
  664. var snd = subNode.SelectSingleNode(pathArr[i]) as XmlElement;
  665. if (snd == null)
  666. {
  667. var nd = doc.CreateElement(pathArr[i]);
  668. subNode.AppendChild(nd);
  669. subNode = nd;
  670. }
  671. else
  672. {
  673. subNode = snd;
  674. }
  675. }
  676. }
  677. foreach (var controlName in module.Value)
  678. {
  679. if (controlName == "StepNo")
  680. {
  681. subNode.SetAttribute(controlName, string.Format("第{0}步", stepIndex + 1));
  682. }
  683. else
  684. {
  685. var recipeRow = RecipeRows.First((o) => o.TechnicalName == controlName);
  686. if (recipeRow == null) continue;
  687. /*to compatiable with old recipe editor, always fill 'black space' to loop step*/
  688. if (controlName == "Loop" && string.IsNullOrEmpty(recipeRow.RecipeItems[stepIndex].Value))
  689. subNode.SetAttribute(controlName, " ");
  690. else
  691. {
  692. subNode.SetAttribute(controlName, recipeRow.RecipeItems[stepIndex].Value);
  693. //bool isJump = recipeRow.RecipeItems[stepIndex].IsJump;
  694. //if (isJump)
  695. //{
  696. // string deviceType = recipeRow.RecipeItems[stepIndex].RecipeVariableDefine.DeviceType;
  697. // if (deviceType == "MFC" || deviceType == "PC")
  698. // subNode.SetAttribute(controlName + ".IsJump", isJump.ToString());
  699. //}
  700. }
  701. }
  702. }
  703. }
  704. }
  705. return doc.OuterXml;
  706. }
  707. /// <summary>
  708. /// expand groups
  709. /// </summary>
  710. private void ExpandGroups()
  711. {
  712. try
  713. {
  714. foreach (CollectionViewGroup item in DataGridControl.Items.Groups)
  715. {
  716. DataGridControl.ExpandGroup(item);
  717. }
  718. }
  719. catch (Exception ex)
  720. {
  721. System.Diagnostics.Debug.WriteLine(ex.Message);
  722. }
  723. }
  724. /// <summary>
  725. /// collapse groups
  726. /// </summary>
  727. private void CollapseGroups()
  728. {
  729. try
  730. {
  731. foreach (CollectionViewGroup item in DataGridControl.Items.Groups)
  732. {
  733. DataGridControl.CollapseGroup(item);
  734. }
  735. }
  736. catch (Exception ex)
  737. {
  738. System.Diagnostics.Debug.WriteLine(ex.Message);
  739. }
  740. }
  741. /// <summary>
  742. /// right click context menu
  743. /// </summary>
  744. private void RightClickAction()
  745. {
  746. DataGridControl.ContextMenu = null;
  747. //get selected column information
  748. List<int> selectedColumns = new List<int>();
  749. foreach (var item in DataGridControl.SelectedCellRanges)
  750. {
  751. bool dir = item.ColumnRange.StartIndex <= item.ColumnRange.EndIndex;
  752. if (dir)
  753. {
  754. for (int i = item.ColumnRange.StartIndex; i <= item.ColumnRange.EndIndex; i++)
  755. {
  756. if (i > 0)
  757. if (!selectedColumns.Contains(i)) selectedColumns.Add(i);
  758. }
  759. }
  760. else
  761. {
  762. for (int i = item.ColumnRange.StartIndex; i >= item.ColumnRange.EndIndex; i--)
  763. {
  764. if (i > 0)
  765. if (!selectedColumns.Contains(i)) selectedColumns.Add(i);
  766. }
  767. }
  768. }
  769. selectedColumns.Sort();
  770. //debug only
  771. /*
  772. string s = "";
  773. foreach (var item in selectedColumns)
  774. {
  775. s += "," + item;
  776. }
  777. MessageBox.Show(s);
  778. * */
  779. //generate context menu
  780. ContextMenu cms = new ContextMenu();
  781. if (selectedColumns.Count > 0)
  782. {
  783. string colStrings = "";
  784. foreach (var item in selectedColumns)
  785. {
  786. if (string.IsNullOrEmpty(colStrings))
  787. colStrings = item.ToString();
  788. else
  789. colStrings += "," + item.ToString();
  790. }
  791. MenuItem mi;
  792. cms.Items.Add(new MenuItem() { Header = string.Format(" 当前选中第{0}步", colStrings), FontFamily = new FontFamily("Arial,SimSun"), IsEnabled = false, Background = Brushes.Gray, Foreground = Brushes.White });
  793. //copy
  794. mi = new MenuItem() { Header = " 复制", FontFamily = new FontFamily("Arial,SimSun"), Tag = selectedColumns.ToList() };
  795. mi.Click += (s, e) =>
  796. {
  797. try
  798. {
  799. var list = (s as MenuItem).Tag as List<int>;
  800. _copiedColumnDatas.Clear();
  801. foreach (var colId in list)
  802. {
  803. _copiedColumnDatas.Add(colId/*index from 1*/, new List<SmartCellData>());
  804. for (int i = 0; i < RecipeRows.Count; i++)
  805. {
  806. var oldCellData = RecipeRows[i].RecipeItems[colId - 1];
  807. var newCellData = new SmartCellData() { Value = oldCellData.Value, RecipeVariableDefine = oldCellData.RecipeVariableDefine };
  808. _copiedColumnDatas[colId].Add(newCellData);
  809. }
  810. }
  811. }
  812. catch (Exception ex)
  813. {
  814. System.Diagnostics.Debug.WriteLine(ex.Message);
  815. }
  816. };
  817. cms.Items.Add(mi);
  818. if (selectedColumns.Count < RecipeRows[0].RecipeItems.Count)
  819. {
  820. mi = new MenuItem() { Header = " 剪切", FontFamily = new FontFamily("Arial,SimSun"), Tag = selectedColumns.ToList() };
  821. mi.Click += (s, e) =>
  822. {
  823. try
  824. {
  825. AddUndoHistory("剪切", CloneRecipeRowData(RecipeRows));
  826. var list = (s as MenuItem).Tag as List<int>;
  827. _copiedColumnDatas.Clear();
  828. foreach (var colId in list)
  829. {
  830. _copiedColumnDatas.Add(colId/*index from 1*/, new List<SmartCellData>());
  831. for (int i = 0; i < RecipeRows.Count; i++)
  832. {
  833. var oldCellData = RecipeRows[i].RecipeItems[colId - 1];
  834. var newCellData = new SmartCellData() { Value = oldCellData.Value, RecipeVariableDefine = oldCellData.RecipeVariableDefine };
  835. _copiedColumnDatas[colId].Add(newCellData);
  836. }
  837. }
  838. foreach (var item in RecipeRows)
  839. {
  840. var collection = new ObservableCollection<SmartCellData>();
  841. for (int index = 0; index < item.RecipeItems.Count; index++)
  842. {
  843. if (list.Contains(index + 1))
  844. continue;
  845. collection.Add(item.RecipeItems[index]);
  846. }
  847. item.RecipeItems = collection;
  848. }
  849. RefreshDataGrid();
  850. RefreshCellsDisplay(false);
  851. }
  852. catch (Exception ex)
  853. {
  854. System.Diagnostics.Debug.WriteLine(ex.Message);
  855. }
  856. };
  857. cms.Items.Add(mi);
  858. mi = new MenuItem() { Header = " 删除", FontFamily = new FontFamily("Arial,SimSun"), Tag = selectedColumns.ToList() };
  859. mi.Click += (s, e) =>
  860. {
  861. try
  862. {
  863. AddUndoHistory("删除", CloneRecipeRowData(RecipeRows));
  864. var list = (s as MenuItem).Tag as List<int>;
  865. foreach (var item in RecipeRows)
  866. {
  867. var collection = new ObservableCollection<SmartCellData>();
  868. for (int index = 0; index < item.RecipeItems.Count; index++)
  869. {
  870. if (list.Contains(index + 1))
  871. continue;
  872. collection.Add(item.RecipeItems[index]);
  873. }
  874. item.RecipeItems = collection;
  875. }
  876. RefreshDataGrid();
  877. RefreshCellsDisplay(false);
  878. }
  879. catch (Exception ex)
  880. {
  881. System.Diagnostics.Debug.WriteLine(ex.Message);
  882. }
  883. };
  884. cms.Items.Add(mi);
  885. }
  886. if (selectedColumns.Count == 1 && _copiedColumnDatas.Count > 0)
  887. {
  888. mi = new MenuItem() { Header = string.Format(" 插入第{0}步后", selectedColumns[0]/*, _copiedColumnDatas.Count*/), FontFamily = new FontFamily("Arial,SimSun"), Tag = selectedColumns[0] };
  889. mi.Click += (s, e) =>
  890. {
  891. try
  892. {
  893. AddUndoHistory("插入", CloneRecipeRowData(RecipeRows));
  894. int insertColId = (int)(s as MenuItem).Tag;
  895. for (int rowIndex = 0; rowIndex < RecipeRows.Count; rowIndex++)
  896. {
  897. var collection = new ObservableCollection<SmartCellData>();
  898. for (int index = 0; index < insertColId; index++)
  899. {
  900. collection.Add(RecipeRows[rowIndex].RecipeItems[index]);
  901. }
  902. foreach (var col in _copiedColumnDatas)
  903. {
  904. collection.Add(new SmartCellData() { Value = col.Value[rowIndex].Value, RecipeVariableDefine = col.Value[rowIndex].RecipeVariableDefine });
  905. }
  906. for (int index = insertColId; index < RecipeRows[rowIndex].RecipeItems.Count; index++)
  907. {
  908. collection.Add(RecipeRows[rowIndex].RecipeItems[index]);
  909. }
  910. RecipeRows[rowIndex].RecipeItems = collection;
  911. }
  912. RefreshDataGrid();
  913. RefreshCellsDisplay(false);
  914. }
  915. catch (Exception ex)
  916. {
  917. System.Diagnostics.Debug.WriteLine(ex.Message);
  918. }
  919. };
  920. cms.Items.Add(mi);
  921. }
  922. }
  923. //show context menu
  924. DataGridControl.ContextMenu = cms;
  925. cms.Visibility = Visibility.Visible;
  926. }
  927. /// <summary>
  928. /// Parse recipe content with recipe format
  929. /// </summary>
  930. /// <param name="recipeFormat"></param>
  931. /// <param name="recipeContent"></param>
  932. /// <param name="selectedStepNo"></param>
  933. public void LoadRecipe(string recipeFormat, string recipeContent, int selectedStepNo = -1)
  934. {
  935. CurrentRunningStepNo = selectedStepNo;
  936. IsHideSameContent = false;
  937. IsRecipeModified = false;
  938. RecipeHead = new RecipeEditor.RecipeHead();
  939. DataGridControl.ContextMenu = null;
  940. RecipeInfo = "";
  941. IsBusy = true;
  942. InvokePropertyChanged("IsBusy");
  943. UndoList.Clear();
  944. RedoList.Clear();
  945. InvokePropertyChanged("UndoList");
  946. InvokePropertyChanged("RedoList");
  947. InvokePropertyChanged("IsUndoEnabled");
  948. InvokePropertyChanged("IsRedoEnabled");
  949. try
  950. {
  951. RecipeRows = new ObservableCollection<RecipeRow>();
  952. _recipeReadingFormat = new Dictionary<string, Dictionary<string, List<RecipeVariableDefine>>>();
  953. _recipeSavingFormat = new Dictionary<string, List<string>>();
  954. //parse recipe format
  955. XmlDocument formatXml = new XmlDocument();
  956. formatXml.LoadXml(recipeFormat);
  957. _currentRecipeFormatContent = formatXml.OuterXml;
  958. //reading recipe variation
  959. string recipeVariationName = formatXml.SelectSingleNode("TableRecipeFormat").Attributes["RecipeVersion"].Value;
  960. if (String.Compare(recipeVariationName, _currentRecipeVariationName) != 0)
  961. {
  962. //if variation name is different from previous loaded recipe -> clear all previous copied recipe columns
  963. _copiedColumnDatas.Clear();
  964. }
  965. _currentRecipeVariationName = recipeVariationName;
  966. //reading recipe validation releated parameters
  967. _preDefinedRecipeVars = new Dictionary<string, string>();
  968. foreach (XmlElement nd in formatXml.SelectNodes("/TableRecipeFormat/Validation/Predefine/Item"))
  969. {
  970. _preDefinedRecipeVars.Add(nd.Attributes["VarName"].Value, nd.Attributes["Value"].Value);
  971. }
  972. //reading check variables
  973. _checkVariables = new List<string>();
  974. foreach (XmlElement nd in formatXml.SelectNodes("/TableRecipeFormat/Validation/CheckVariable/Var"))
  975. {
  976. string varName = nd.Attributes["Name"].Value;
  977. _checkVariables.Add(varName);
  978. }
  979. //reading validation rules
  980. _validationRules = new List<Tuple<string, string, string>>();
  981. foreach (XmlElement nd in formatXml.SelectNodes("/TableRecipeFormat/Validation/Restriction/Rule"))
  982. {
  983. string varName = nd.Attributes["VarName"].Value;
  984. string checkCondition = nd.Attributes["CheckCondition"].Value.Replace("&lt;", "<").Replace("&gt;", ">");
  985. string message = nd.Attributes["Message"].Value.Replace("'", "\"");
  986. _validationRules.Add(new Tuple<string, string, string>(varName, checkCondition, message));
  987. }
  988. //parsing recipe format xml file
  989. foreach (XmlElement catalogNode in formatXml.SelectNodes("/TableRecipeFormat/Catalog"))
  990. {
  991. string catalogName = catalogNode.Attributes["DisplayName"].Value;
  992. _recipeReadingFormat.Add(catalogName, new Dictionary<string, List<RecipeVariableDefine>>());
  993. foreach (XmlElement groupNode in catalogNode.SelectNodes("Group"))
  994. {
  995. string groupName = groupNode.Attributes["DisplayName"].Value;
  996. _recipeReadingFormat[catalogName].Add(groupName, new List<RecipeVariableDefine>());
  997. foreach (XmlElement stepNode in groupNode.SelectNodes("Step"))
  998. {
  999. string stepModuleName = stepNode.Attributes["ModuleName"].Value;
  1000. string stepDeviceType = stepNode.Attributes["DeviceType"].Value;
  1001. string stepDisplayName = stepNode.Attributes["DisplayName"].Value;
  1002. string stepControlName = stepNode.Attributes["ControlName"].Value;
  1003. string stepInputType = stepNode.Attributes["InputType"].Value;
  1004. string stepDescription = stepNode.HasAttribute("Desc") ? stepNode.Attributes["Desc"].Value : "";
  1005. double stepMin = double.Parse(stepNode.HasAttribute("Min") ? stepNode.Attributes["Min"].Value : "0");
  1006. double stepMax = double.Parse(stepNode.HasAttribute("Max") ? stepNode.Attributes["Max"].Value : "0");
  1007. var selectionList = new List<Tuple<string, string>>();
  1008. foreach (XmlElement selectionNode in stepNode.SelectNodes("Item"))
  1009. {
  1010. selectionList.Add(new Tuple<string, string>(selectionNode.Attributes["ControlName"].Value, selectionNode.Attributes["DisplayName"].Value));
  1011. }
  1012. if (!_recipeSavingFormat.ContainsKey(stepModuleName)) _recipeSavingFormat.Add(stepModuleName, new List<string>());
  1013. _recipeSavingFormat[stepModuleName].Add(stepControlName);
  1014. if (stepControlName == "StepNo")
  1015. continue;
  1016. _recipeReadingFormat[catalogName][groupName].Add(new RecipeVariableDefine()
  1017. {
  1018. CellType = (CellType)Enum.Parse(typeof(CellType), stepInputType),
  1019. Description = stepDescription,
  1020. DeviceType = stepDeviceType,
  1021. DropdownItemList = selectionList,
  1022. MaxValue = stepMax,
  1023. //MinValue = stepDeviceType.Equals("MFC",StringComparison.InvariantCultureIgnoreCase)? stepMax*2.0/100: stepMin,
  1024. MinValue = stepMin,
  1025. GroupName = groupName,
  1026. CatalogName = catalogName,
  1027. TechnicalName = stepControlName,
  1028. FriendlyName = stepDisplayName
  1029. });
  1030. }
  1031. }
  1032. }
  1033. //parse recipe content
  1034. XmlDocument contentXml = new XmlDocument();
  1035. contentXml.LoadXml(recipeContent);
  1036. contentXml.DocumentElement.SetAttribute("RecipeVersion", _currentRecipeVariationName);
  1037. //read recipe head
  1038. //em. RecipeVersion="Ace" CreatedBy="tech" CreationTime="2013-02-02T12:36:02" LastRevisedBy="Peter" LastRevisionTime="2013-10-22T13:30:29" Description="5e46af80-49f9-4b4f-b04b-bc911fb292f8"
  1039. RecipeHead.CreatedBy = contentXml.DocumentElement.HasAttribute("CreatedBy") ? contentXml.DocumentElement.Attributes["CreatedBy"].Value : "(无)";
  1040. RecipeHead.CreationTime = contentXml.DocumentElement.HasAttribute("CreationTime") ? contentXml.DocumentElement.Attributes["CreationTime"].Value : "(无)";
  1041. RecipeHead.LastModifiedBy = contentXml.DocumentElement.HasAttribute("LastRevisedBy") ? contentXml.DocumentElement.Attributes["LastRevisedBy"].Value : "(无)";
  1042. RecipeHead.LastRevisionTime = contentXml.DocumentElement.HasAttribute("LastRevisionTime") ? contentXml.DocumentElement.Attributes["LastRevisionTime"].Value : "(无)";
  1043. if (contentXml.DocumentElement.HasAttribute("PressureMode"))
  1044. {
  1045. RecipeHead.PressureMode = contentXml.DocumentElement.Attributes["PressureMode"].Value;
  1046. }
  1047. if (contentXml.DocumentElement.HasAttribute("BasePressure"))
  1048. {
  1049. RecipeHead.BasePressure = contentXml.DocumentElement.Attributes["BasePressure"].Value;
  1050. }
  1051. if (contentXml.DocumentElement.HasAttribute("PumpDownLimit"))
  1052. {
  1053. RecipeHead.PumpDownLimit = contentXml.DocumentElement.Attributes["PumpDownLimit"].Value;
  1054. }
  1055. if (contentXml.DocumentElement.HasAttribute("ElectrodeTemp"))
  1056. {
  1057. RecipeHead.ElectrodeTemp = contentXml.DocumentElement.Attributes["ElectrodeTemp"].Value;
  1058. }
  1059. if (contentXml.DocumentElement.HasAttribute("PurgeActive"))
  1060. {
  1061. RecipeHead.PurgeActive = contentXml.DocumentElement.Attributes["PurgeActive"].Value;
  1062. }
  1063. if (contentXml.DocumentElement.HasAttribute("Barcode"))
  1064. {
  1065. RecipeHead.Barcode = contentXml.DocumentElement.Attributes["Barcode"].Value;
  1066. }
  1067. RecipeHead.RecipeVariation = contentXml.DocumentElement.HasAttribute("RecipeVersion") ? contentXml.DocumentElement.Attributes["RecipeVersion"].Value : "(NULL)";
  1068. RecipeHead.Description = contentXml.DocumentElement.HasAttribute("Description") ? contentXml.DocumentElement.Attributes["Description"].Value : "(NULL)";
  1069. var allRecipeItems = new List<Dictionary<string, string>>();
  1070. foreach (XmlElement stepNode in contentXml.SelectNodes("/TableRecipeData/Step"))
  1071. {
  1072. var stepDic = new Dictionary<string, string>();
  1073. allRecipeItems.Add(stepDic);
  1074. foreach (XmlAttribute att in stepNode.Attributes)
  1075. {
  1076. stepDic.Add(att.Name, att.Value);
  1077. }
  1078. foreach (XmlElement innerStep in stepNode.ChildNodes)
  1079. {
  1080. foreach (XmlAttribute att in innerStep.Attributes)
  1081. {
  1082. stepDic.Add(att.Name, att.Value);
  1083. }
  1084. foreach (XmlElement innerInnerStep in innerStep.ChildNodes)
  1085. {
  1086. foreach (XmlAttribute att in innerInnerStep.Attributes)
  1087. {
  1088. stepDic.Add(att.Name, att.Value);
  1089. }
  1090. }
  1091. }
  1092. }
  1093. //generate view model
  1094. RowVarNameDic = new Dictionary<string, int>();
  1095. int rowIndex = 0;
  1096. foreach (var catalog in _recipeReadingFormat.Keys)
  1097. {
  1098. foreach (var group in _recipeReadingFormat[catalog].Keys)
  1099. {
  1100. foreach (var var1 in _recipeReadingFormat[catalog][group])
  1101. {
  1102. var singleRow = new RecipeRow() { CatalogName = catalog, FriendlyName = /*group + */var1.FriendlyName, TechnicalName = var1.TechnicalName };
  1103. for (int stepNo = 0; stepNo < allRecipeItems.Count; stepNo++)
  1104. {
  1105. var stepCell = new SmartCellData() { RecipeVariableDefine = var1 };
  1106. if (allRecipeItems[stepNo].ContainsKey(var1.TechnicalName))
  1107. {
  1108. stepCell.Value = allRecipeItems[stepNo][var1.TechnicalName];
  1109. //stepCell.ShowsJumpControl = false;
  1110. //if (var1.CellType == CellType.NumInput)
  1111. //{
  1112. // if (var1.DeviceType == "MFC" || var1.DeviceType == "PC")
  1113. // {
  1114. // string jumpString = var1.TechnicalName + ".IsJump";
  1115. // stepCell.IsJump = allRecipeItems[stepNo].ContainsKey(jumpString) ? bool.Parse(allRecipeItems[stepNo][jumpString]) : false;
  1116. // stepCell.ShowsJumpControl = true;
  1117. // }
  1118. //}
  1119. }
  1120. else
  1121. stepCell.Value = "n/a";
  1122. singleRow.RecipeItems.Add(stepCell);
  1123. }
  1124. RecipeRows.Add(singleRow);
  1125. RowVarNameDic.Add(var1.TechnicalName, rowIndex++);
  1126. }
  1127. }
  1128. }
  1129. //refresh datagrid
  1130. RefreshDataGrid();
  1131. //refresh recipe information
  1132. RefreshCellsDisplay();
  1133. if (OnLoadRecipeContent != null)
  1134. OnLoadRecipeContent.Invoke(recipeContent, null);
  1135. }
  1136. catch (Exception ex)
  1137. {
  1138. System.Diagnostics.Debug.WriteLine(ex.Message);
  1139. //LOG.Write("", ex);
  1140. }
  1141. IsBusy = false;
  1142. InvokePropertyChanged("IsBusy");
  1143. }
  1144. /// <summary>
  1145. /// 检查变量ramp rate
  1146. /// </summary>
  1147. /// <param name="stepNo"></param>
  1148. /// <param name="rampEnable"></param>
  1149. /// <param name="varName"></param>
  1150. /// <param name="rampTime"></param>
  1151. /// <param name="maxRampUpRate"></param>
  1152. /// <param name="maxRampDownRate"></param>
  1153. /// <returns>False:check ok, True: check failed</returns>
  1154. public bool CheckRampRate(int stepNo, string rampEnable, string varName, string rampTime, double maxRampUpRate, double maxRampDownRate)
  1155. {
  1156. try
  1157. {
  1158. if (stepNo <= 0) return false;
  1159. int rowIndex = RowVarNameDic[varName];
  1160. double currentValue = double.Parse(RecipeRows[rowIndex].RecipeItems[stepNo].Value);
  1161. //if (varName == "AZone.Setpoint" || varName == "BZone.Setpoint" || varName == "CZone.Setpoint" || varName == "DZone.Setpoint")
  1162. //{
  1163. // int heatControlModeIndex = RowVarNameDic["Heater.Mode"];
  1164. // string curStepHeatCtrlMode = RecipeRows[heatControlModeIndex].RecipeItems[stepNo].Value;
  1165. // string lastStepHeatCtrlMode = RecipeRows[heatControlModeIndex].RecipeItems[stepNo - 1].Value;
  1166. // if (curStepHeatCtrlMode != lastStepHeatCtrlMode)
  1167. // {
  1168. // if (!(lastStepHeatCtrlMode.Equals("CurrentControl") && curStepHeatCtrlMode.Equals("PyroTempControl")))
  1169. // return false;
  1170. // int endbyIndex = RowVarNameDic["EndBy"];
  1171. // int endValueIndex = RowVarNameDic["EndValue"];
  1172. // string endby = RecipeRows[endbyIndex].RecipeItems[stepNo - 1].Value;
  1173. // EndByCondition endbyEnum;
  1174. // if (!Enum.TryParse(endby, out endbyEnum)) return false;
  1175. // if (endbyEnum != EndByCondition.PmTempGt && endbyEnum != EndByCondition.PmTempLt) return false;
  1176. // string end = RecipeRows[endValueIndex].RecipeItems[stepNo - 1].Value;
  1177. // double endValue;
  1178. // if (!double.TryParse(end, out endValue)) return false;
  1179. // return CheckRampRate(rampEnable, rampTime, maxRampUpRate, maxRampDownRate, endValue, currentValue);
  1180. // }
  1181. //}
  1182. double prevValue = double.Parse(RecipeRows[rowIndex].RecipeItems[stepNo - 1].Value);
  1183. return CheckRampRate(rampEnable, rampTime, maxRampUpRate, maxRampDownRate, prevValue, currentValue);
  1184. }
  1185. catch (Exception ex)
  1186. {
  1187. System.Diagnostics.Debug.WriteLine(ex.Message);
  1188. return true;
  1189. }
  1190. }
  1191. bool CheckRampRate(string rampEnable, string rampTime, double maxRampUpRate, double maxRampDownRate, double prevValue, double currentValue)
  1192. {
  1193. bool isRampEnable = bool.Parse(rampEnable);
  1194. //string[] timeStr = rampTime.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries);
  1195. //string tt = string.Join(":", timeStr);
  1196. TimeSpan timeSpan;
  1197. TimeSpan.TryParse(rampTime, out timeSpan);
  1198. double totalTimeSec = timeSpan.TotalSeconds;
  1199. double diff = currentValue - prevValue;
  1200. if (!isRampEnable || totalTimeSec <= 0)
  1201. {
  1202. if (diff != 0) return true;
  1203. return false;
  1204. }
  1205. else
  1206. {
  1207. double rampRate = diff / totalTimeSec;
  1208. return (rampRate > 0 && rampRate >= maxRampUpRate) || (rampRate < 0 && rampRate <= -maxRampDownRate);
  1209. }
  1210. }
  1211. /// <summary>
  1212. /// Refresh datagrid cell data display
  1213. /// </summary>
  1214. /// <param name="moving2RunningStepPosition">True: moving to current running step position</param>
  1215. public void RefreshCellsDisplay(bool moving2RunningStepPosition = true)
  1216. {
  1217. try
  1218. {
  1219. if (RecipeRows == null || RecipeRows.Count < 2)
  1220. return;
  1221. Errors = new List<Tuple<int, int, string, string>>();
  1222. Dictionary<int, string> dicEndby = new Dictionary<int, string>();
  1223. Dictionary<int, string> dicPressureMode = new Dictionary<int, string>();
  1224. Dictionary<int, string> dicRfMode = new Dictionary<int, string>();
  1225. Dictionary<int, string> dicRfMatchProcessMode = new Dictionary<int, string>();
  1226. for (int i = 0; i < RecipeRows.Count; i++)
  1227. {
  1228. for (int j = 0; j < RecipeRows[i].RecipeItems.Count; j++)
  1229. {
  1230. var cell = RecipeRows[i].RecipeItems[j];
  1231. cell.RowIndex = i;
  1232. cell.ColIndex = j;
  1233. cell.ErrInfo = string.Empty;
  1234. bool logicEnable = true;
  1235. if (cell.RecipeVariableDefine.TechnicalName == "EndBy")
  1236. dicEndby[j] = cell.Value;
  1237. if (cell.RecipeVariableDefine.TechnicalName == "ThrottleValve.SetMode")
  1238. {
  1239. dicPressureMode[j] = cell.Value;
  1240. }
  1241. if (cell.RecipeVariableDefine.TechnicalName == "PressureControl.SetTVMode")
  1242. {
  1243. dicPressureMode[j] = cell.Value;
  1244. }
  1245. if (cell.RecipeVariableDefine.TechnicalName == "Rf.SetMode")
  1246. dicRfMode[j] = cell.Value;
  1247. if (cell.RecipeVariableDefine.TechnicalName == "Rf.SetMatchProcessMode")
  1248. dicRfMatchProcessMode[j] = cell.Value;
  1249. if (cell.RecipeVariableDefine.TechnicalName == "Time")
  1250. {
  1251. logicEnable = dicEndby.ContainsKey(j) && (dicEndby[j] == "EndByStepTime" || dicEndby[j] == "EndByHeatUp");
  1252. }
  1253. if (cell.RecipeVariableDefine.TechnicalName == "ThrottleValve.SetPosition")
  1254. {
  1255. logicEnable = dicPressureMode.ContainsKey(j) && dicPressureMode[j] == "TVPositionCtrl";
  1256. }
  1257. if (cell.RecipeVariableDefine.TechnicalName == "ThrottleValve.SetPressure")
  1258. {
  1259. logicEnable = dicPressureMode.ContainsKey(j) && dicPressureMode[j] == "TVPressureCtrl";
  1260. }
  1261. if (cell.RecipeVariableDefine.TechnicalName == "PressureControl.SetTVPosition")
  1262. {
  1263. logicEnable = dicPressureMode.ContainsKey(j) && dicPressureMode[j] == "TVPositionCtrl";
  1264. }
  1265. if (cell.RecipeVariableDefine.TechnicalName == "PressureControl.SetTVPressure")
  1266. {
  1267. logicEnable = dicPressureMode.ContainsKey(j) && dicPressureMode[j] == "TVPressureCtrl";
  1268. }
  1269. if (cell.RecipeVariableDefine.TechnicalName == "Rf.SetPulsingFrequency")
  1270. {
  1271. logicEnable = dicRfMode.ContainsKey(j) && dicRfMode[j] == "PulsingMode";
  1272. }
  1273. if (cell.RecipeVariableDefine.TechnicalName == "Rf.SetPulsingDuty")
  1274. {
  1275. logicEnable = dicRfMode.ContainsKey(j) && dicRfMode[j] == "PulsingMode";
  1276. }
  1277. if (cell.RecipeVariableDefine.TechnicalName == "Rf.SetPowerOnTime")
  1278. {
  1279. logicEnable = dicEndby.ContainsKey(j) && dicEndby[j] == "EndByRfTime";
  1280. }
  1281. //if (cell.RecipeVariableDefine.TechnicalName == "Rf.SetMatchPositionC1")
  1282. //{
  1283. // logicEnable = dicRfMatchProcessMode.ContainsKey(j);// && dicRfMatchProcessMode[j] == "TritonPresetMode";
  1284. //}
  1285. //if (cell.RecipeVariableDefine.TechnicalName == "Rf.SetMatchPositionC2")
  1286. //{
  1287. // logicEnable = dicRfMatchProcessMode.ContainsKey(j);// && dicRfMatchProcessMode[j] == "TritonPresetMode";
  1288. //}
  1289. cell.IsMasked = !logicEnable;
  1290. //update diff variable numbers
  1291. if (cell.RecipeVariableDefine.TechnicalName == "Ramp")
  1292. {
  1293. //更新当前步骤中Ramp的变量数据
  1294. if (j == 0)
  1295. {
  1296. cell.Tag = 0;
  1297. }
  1298. else
  1299. {
  1300. int rampNum = 0;
  1301. for (int s1 = 0; s1 < RecipeRows.Count; s1++)
  1302. {
  1303. if (RecipeRows[s1].CatalogName == "StepInfo")// RecipeRows[s1].RecipeItems[j].RecipeVariableDefine.CellType == CellType.ReadOnly)
  1304. continue;
  1305. string preValue = RecipeRows[s1].RecipeItems[j - 1].Value;
  1306. string curValue = RecipeRows[s1].RecipeItems[j].Value;
  1307. if (RecipeRows[s1].RecipeItems[j].RecipeVariableDefine.CellType == CellType.NumInput)
  1308. {
  1309. double pd, cd;
  1310. if (double.TryParse(preValue, out pd) && double.TryParse(curValue, out cd))
  1311. if (pd != cd) rampNum++;
  1312. }
  1313. else if (String.Compare(preValue, curValue, false) != 0)
  1314. {
  1315. rampNum++;
  1316. }
  1317. }
  1318. cell.Tag = rampNum;
  1319. }
  1320. cell.InvokePropertyChanged();
  1321. }
  1322. #region mask (hide or show cell content)
  1323. if ((MaskedTechNames != null && MaskedTechNames.Contains(cell.RecipeVariableDefine.TechnicalName)) ||
  1324. (MaskedCatalogNames != null && MaskedCatalogNames.Contains(cell.RecipeVariableDefine.CatalogName)) || !logicEnable)
  1325. cell.IsMasked = true;
  1326. else
  1327. cell.IsMasked = false;
  1328. #endregion mask (hide or show cell content)
  1329. #region check cell data range
  1330. switch (cell.RecipeVariableDefine.CellType)
  1331. {
  1332. case CellType.CheckBox:
  1333. {
  1334. if (string.Compare(cell.Value, "true", true) == 0 || string.Compare(cell.Value, "false", true) == 0)
  1335. {
  1336. cell.ErrInfo = "";
  1337. cell.Background = Brushes.Transparent;
  1338. }
  1339. else
  1340. {
  1341. string reason = string.Format("Value '{0}' not valid", cell.Value);
  1342. Errors.Add(new Tuple<int, int, string, string>(i, j, cell.RecipeVariableDefine.FriendlyName, reason));
  1343. cell.ErrInfo = reason;
  1344. cell.Background = Brushes.Pink;
  1345. }
  1346. }
  1347. break;
  1348. case CellType.EditableSelection:
  1349. {
  1350. cell.ErrInfo = "";
  1351. cell.Background = Brushes.Transparent;
  1352. }
  1353. break;
  1354. case CellType.NumInput:
  1355. {
  1356. double min = cell.RecipeVariableDefine.MinValue;
  1357. double max = cell.RecipeVariableDefine.MaxValue;
  1358. double v;
  1359. if (!double.TryParse(cell.Value, out v))
  1360. {
  1361. string reason = string.Format("Value '{0}' not valid", cell.Value);
  1362. Errors.Add(new Tuple<int, int, string, string>(i, j, cell.RecipeVariableDefine.FriendlyName, reason));
  1363. cell.ErrInfo = reason;
  1364. cell.Background = Brushes.Pink;
  1365. }
  1366. else if (v > max || v < 0 || (v < min && v > max * 0.1 / 100))
  1367. {
  1368. string reason = string.Format("Value'{0}',Out of Range {1}~{2}", cell.Value, min, max);
  1369. Errors.Add(new Tuple<int, int, string, string>(i, j, cell.RecipeVariableDefine.FriendlyName, reason));
  1370. cell.ErrInfo = reason;
  1371. cell.Background = Brushes.Pink;
  1372. }
  1373. else
  1374. {
  1375. cell.ErrInfo = "";
  1376. cell.Background = Brushes.Transparent;
  1377. }
  1378. }
  1379. break;
  1380. case CellType.ReadOnlySelection:
  1381. {
  1382. if (cell.RecipeVariableDefine.DropdownItemList != null && cell.RecipeVariableDefine.DropdownItemList.Find((o) => o.Item1 == cell.Value) != null)
  1383. {
  1384. cell.ErrInfo = "";
  1385. cell.Background = Brushes.Transparent;
  1386. }
  1387. else
  1388. {
  1389. string reason = string.Format("Value'{0}' is not valid", cell.Value);
  1390. Errors.Add(new Tuple<int, int, string, string>(i, j, cell.RecipeVariableDefine.FriendlyName, reason));
  1391. cell.ErrInfo = reason;
  1392. cell.Background = Brushes.Pink;
  1393. }
  1394. }
  1395. break;
  1396. case CellType.ReadOnly:
  1397. case CellType.TextInput:
  1398. cell.ErrInfo = "";
  1399. cell.Background = Brushes.Transparent;
  1400. break;
  1401. case CellType.TimeInput:
  1402. {
  1403. string[] arr = cell.Value.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries);
  1404. int h, mi, s;
  1405. if (arr.Length == 3 && int.TryParse(arr[0], out h) && int.TryParse(arr[1], out mi) && int.TryParse(arr[2], out s) && h >= 0 && mi >= 0 && mi <= 59 && s >= 0 && s <= 59)
  1406. {
  1407. cell.ErrInfo = "";
  1408. cell.Background = Brushes.Transparent;
  1409. }
  1410. else
  1411. {
  1412. string reason = string.Format("value'{0}' is not valid", cell.Value);
  1413. Errors.Add(new Tuple<int, int, string, string>(i, j, cell.RecipeVariableDefine.FriendlyName, reason));
  1414. cell.ErrInfo = reason;
  1415. cell.Background = Brushes.Pink;
  1416. }
  1417. }
  1418. break;
  1419. }
  1420. #endregion check cell data range
  1421. #region mark data trend / hide same content
  1422. if (j == 0) //step one
  1423. {
  1424. cell.Foreground = Brushes.Black;
  1425. cell.FontWeight = FontWeights.Normal;
  1426. cell.IsHidden = false;
  1427. cell.InvokePropertyChanged();
  1428. cell.IsMasked = !logicEnable;
  1429. continue;
  1430. }
  1431. var preCell = RecipeRows[i].RecipeItems[j - 1];
  1432. if (cell.RecipeVariableDefine.CellType == CellType.NumInput)
  1433. {
  1434. double preValue = 0;
  1435. double.TryParse(preCell.Value.ToString(), out preValue);
  1436. double curValue = 0;
  1437. double.TryParse(cell.Value.ToString(), out curValue);
  1438. if (curValue > preValue)
  1439. {
  1440. cell.Foreground = Brushes.Red;
  1441. cell.FontWeight = FontWeights.Bold;
  1442. }
  1443. else if (curValue < preValue)
  1444. {
  1445. cell.Foreground = Brushes.Blue;
  1446. cell.FontWeight = FontWeights.Bold;
  1447. }
  1448. else
  1449. {
  1450. cell.Foreground = Brushes.Black;
  1451. cell.FontWeight = FontWeights.Normal;
  1452. }
  1453. }
  1454. else
  1455. {
  1456. //not number type
  1457. cell.Foreground = Brushes.Black;
  1458. cell.FontWeight = FontWeights.Normal;
  1459. }
  1460. if (IsHideSameContent && cell.Value == preCell.Value)
  1461. cell.IsHidden = true;
  1462. else
  1463. cell.IsHidden = false;
  1464. //!logicEnable;
  1465. cell.IsMasked = !logicEnable;
  1466. //if (!logicEnable)
  1467. //{
  1468. // cell.Background = Brushes.DarkGray;
  1469. // cell.IsMasked = true;
  1470. //}
  1471. #endregion mark data trend / hide same content
  1472. cell.InvokePropertyChanged();
  1473. }
  1474. }
  1475. #region check loop
  1476. int loopRowId = -1;
  1477. for (int i = 0; i < RecipeRows.Count; i++)
  1478. {
  1479. if (RecipeRows[i].TechnicalName == "Loop")
  1480. {
  1481. loopRowId = i;
  1482. break;
  1483. }
  1484. }
  1485. for (int j = 0; j < RecipeRows[loopRowId].RecipeItems.Count; j++)
  1486. {
  1487. var cell = RecipeRows[loopRowId].RecipeItems[j];
  1488. bool isLoopStart = Regex.IsMatch(cell.Value, @"^Loop\x20\d+$") || Regex.IsMatch(cell.Value, @"^循环\x20\d+$");
  1489. bool isLoopEnd = Regex.IsMatch(cell.Value, @"^Loop End$") || Regex.IsMatch(cell.Value, @"^循环结束");
  1490. bool isNullOrEmpty = string.IsNullOrWhiteSpace(cell.Value);
  1491. if (!isLoopEnd && !isLoopStart && !isNullOrEmpty)
  1492. {
  1493. string reason = string.Format("Value '{0}' not valid", cell.Value);
  1494. cell.ErrInfo = reason;
  1495. cell.Background = Brushes.Pink;
  1496. Errors.Add(new Tuple<int, int, string, string>(loopRowId, j, cell.RecipeVariableDefine.FriendlyName, reason));
  1497. }
  1498. if (isLoopEnd)
  1499. {
  1500. string reason = "Loop Start 缺失";
  1501. cell.ErrInfo = reason;
  1502. cell.Background = Brushes.Pink;
  1503. Errors.Add(new Tuple<int, int, string, string>(loopRowId, j, cell.RecipeVariableDefine.FriendlyName, reason));
  1504. }
  1505. else if (isLoopStart)
  1506. {
  1507. for (int k = j + 1; k < RecipeRows[loopRowId].RecipeItems.Count; k++)
  1508. {
  1509. cell = RecipeRows[loopRowId].RecipeItems[k];
  1510. bool isCurStepLoopStart = Regex.IsMatch(cell.Value, @"^Loop\x20\d+$") || Regex.IsMatch(cell.Value, @"^循环\x20\d+$");
  1511. bool isCurStepLoopEnd = Regex.IsMatch(cell.Value, @"^Loop End$") || Regex.IsMatch(cell.Value, @"^循环结束");
  1512. isNullOrEmpty = string.IsNullOrWhiteSpace(cell.Value);
  1513. if (!isCurStepLoopEnd && !isCurStepLoopStart && !isNullOrEmpty)
  1514. {
  1515. string reason = string.Format("Value '{0}' not valid", cell.Value);
  1516. cell.ErrInfo = reason;
  1517. cell.Background = Brushes.Pink;
  1518. Errors.Add(new Tuple<int, int, string, string>(loopRowId, k, cell.RecipeVariableDefine.FriendlyName, reason));
  1519. }
  1520. else if (isCurStepLoopStart)
  1521. {
  1522. string reason = "前面循环没有结束,不能设置新的Loop Start标志";
  1523. cell.ErrInfo = reason;
  1524. cell.Background = Brushes.Pink;
  1525. Errors.Add(new Tuple<int, int, string, string>(loopRowId, k, cell.RecipeVariableDefine.FriendlyName, reason));
  1526. }
  1527. else if (isCurStepLoopEnd)
  1528. {
  1529. //mark loop steps with blue background
  1530. for (int m1 = j; m1 <= k; m1++)
  1531. {
  1532. var curCell = RecipeRows[loopRowId].RecipeItems[m1];
  1533. if (curCell.Background == Brushes.Transparent)
  1534. curCell.Background = Brushes.LightGreen;
  1535. curCell.InvokePropertyChanged();
  1536. }
  1537. j = k;
  1538. break;
  1539. }
  1540. if (k == RecipeRows[loopRowId].RecipeItems.Count - 1)
  1541. {
  1542. j = k;
  1543. string reason = "Loop End 缺失";
  1544. cell.ErrInfo = reason;
  1545. cell.Background = Brushes.Pink;
  1546. Errors.Add(new Tuple<int, int, string, string>(loopRowId, k, cell.RecipeVariableDefine.FriendlyName, reason));
  1547. }
  1548. }
  1549. }
  1550. }
  1551. #endregion check loop
  1552. #region recipe parameter validation
  1553. using (var lua = new LuaInterface.Lua())
  1554. {
  1555. //is special recipe?
  1556. //bool IsSpecialRecipe = true;
  1557. //{
  1558. // int heaterModeRowIndex = RowVarNameDic["Heater.Mode"];
  1559. // int aZoneSetpointIndex = RowVarNameDic["AZone.Setpoint"];
  1560. // int bZoneSetpointIndex = RowVarNameDic["BZone.Setpoint"];
  1561. // int cZoneSetpointIndex = RowVarNameDic["CZone.Setpoint"];
  1562. // int dZoneSetpointIndex = RowVarNameDic.ContainsKey("DZone.Setpoint") ? RowVarNameDic["DZone.Setpoint"] : aZoneSetpointIndex;
  1563. // for (int stepIndex = 0; stepIndex < RecipeRows[0].RecipeItems.Count; stepIndex++)
  1564. // {
  1565. // if (RecipeRows[heaterModeRowIndex].RecipeItems[stepIndex].Value != "CurrentControl" ||
  1566. // RecipeRows[aZoneSetpointIndex].RecipeItems[stepIndex].Value != "0" ||
  1567. // RecipeRows[bZoneSetpointIndex].RecipeItems[stepIndex].Value != "0" ||
  1568. // RecipeRows[cZoneSetpointIndex].RecipeItems[stepIndex].Value != "0" ||
  1569. // RecipeRows[dZoneSetpointIndex].RecipeItems[stepIndex].Value != "0")
  1570. // {
  1571. // IsSpecialRecipe = false;
  1572. // break;
  1573. // }
  1574. // }
  1575. //}
  1576. ////set get ramp rate function
  1577. //lua.RegisterFunction("CheckRampRate", this, GetType().GetMethod("CheckRampRate"));
  1578. //lua.DoString(string.Format("IsProductionRecipe={0};",(!IsSpecialRecipe).ToString().ToLower()));
  1579. for (int stepIndex = 0; stepIndex < RecipeRows[0].RecipeItems.Count; stepIndex++)
  1580. {
  1581. //set stepNo
  1582. lua.DoString(string.Format("StepNo={0};", stepIndex));
  1583. //reading var from current recipe step
  1584. foreach (var checkVar in _checkVariables)
  1585. {
  1586. if (!RowVarNameDic.ContainsKey(checkVar))
  1587. {
  1588. System.Diagnostics.Debug.WriteLine("检查不到变量定义," + checkVar);
  1589. continue;
  1590. }
  1591. try
  1592. {
  1593. int varId = RowVarNameDic[checkVar];
  1594. if (RecipeRows[varId].RecipeItems[stepIndex].RecipeVariableDefine.CellType == CellType.NumInput)
  1595. lua.DoString(string.Format("{0}={1};", RecipeRows[varId].RecipeItems[stepIndex].RecipeVariableDefine.TechnicalName.Replace(".", "_"), RecipeRows[varId].RecipeItems[stepIndex].Value));
  1596. else
  1597. lua.DoString(string.Format("{0}=\"{1}\";", RecipeRows[varId].RecipeItems[stepIndex].RecipeVariableDefine.TechnicalName.Replace(".", "_"), RecipeRows[varId].RecipeItems[stepIndex].Value));
  1598. }
  1599. catch (Exception ex)
  1600. {
  1601. System.Diagnostics.Debug.WriteLine("校验异常," + ex);
  1602. }
  1603. }
  1604. //reading from recipe format file
  1605. foreach (string key in _preDefinedRecipeVars.Keys)
  1606. {
  1607. string varValueString = _preDefinedRecipeVars[key];
  1608. double varValue;
  1609. if (double.TryParse(varValueString, out varValue))
  1610. lua.DoString(string.Format("{0}={1};", key, varValue));
  1611. else
  1612. lua.DoString(string.Format("{0}=\"{1}\";", key, varValueString));
  1613. }
  1614. //do valation
  1615. foreach (var rule in _validationRules)
  1616. {
  1617. lua.DoString(string.Format("if {0} then hasErr=1 else hasErr=0 end", rule.Item2));
  1618. bool hasError = ((int)lua.GetNumber("hasErr")) == 1;
  1619. if (hasError)
  1620. {
  1621. lua.DoString(string.Format("message=string.format({0});", rule.Item3));
  1622. string reason = lua.GetString("message");
  1623. var rowId = RowVarNameDic[rule.Item1];
  1624. var cell = RecipeRows[rowId].RecipeItems[stepIndex];
  1625. cell.ErrInfo = reason;
  1626. cell.Background = Brushes.Pink;
  1627. Errors.Add(new Tuple<int, int, string, string>(rowId, stepIndex, cell.RecipeVariableDefine.FriendlyName, reason));
  1628. cell.InvokePropertyChanged();
  1629. }
  1630. }
  1631. }
  1632. }
  1633. #endregion recipe parameter validation
  1634. #region update material cell data
  1635. int materialRowId = -1;
  1636. for (int colId = 0; colId < RecipeRows[0].RecipeItems.Count; colId++)
  1637. {
  1638. string materialName = "";
  1639. for (int rowId = 0; rowId < RecipeRows.Count; rowId++)
  1640. {
  1641. string curMo = "";
  1642. if (materialRowId == -1 && RecipeRows[rowId].RecipeItems[colId].RecipeVariableDefine.TechnicalName == "Material")
  1643. {
  1644. materialRowId = rowId;
  1645. }
  1646. var cell = RecipeRows[rowId].RecipeItems[colId];
  1647. if (cell.RecipeVariableDefine.CellType == CellType.ReadOnlySelection && String.Compare(cell.Value, "flow", true) == 0)
  1648. {
  1649. string moName = cell.RecipeVariableDefine.TechnicalName.Split('.')[0].ToLower();
  1650. string displayName = cell.RecipeVariableDefine.FriendlyName.Replace("_", ".").Split('.')[0].ToLower();
  1651. if (moName.Contains("cp2mg_1") || displayName.Contains("cp2mg_1")) curMo = "Mg1";
  1652. else if (moName.Contains("cp2mg_2") || displayName.Contains("cp2mg_2")) curMo = "Mg2";
  1653. else if (moName.Contains("cp2mg_3") || displayName.Contains("cp2mg_3")) curMo = "Mg3";
  1654. else if (moName.Contains("cp2mg_4") || displayName.Contains("cp2mg_4")) curMo = "Mg4";
  1655. else if (moName.Contains("cp2mg") || displayName.Contains("cp2mg")) curMo = "Mg";
  1656. else if (moName.Contains("tmin") || displayName.Contains("tmin")) curMo = "In";
  1657. else if (moName.Contains("tmin_1") || displayName.Contains("tmin_1")) curMo = "In1";
  1658. else if (moName.Contains("tmin_2") || displayName.Contains("tmin_2")) curMo = "In2";
  1659. else if (moName.Contains("tmin_3") || displayName.Contains("tmin_3")) curMo = "In3";
  1660. else if (moName.Contains("tmin_4") || displayName.Contains("tmin_4")) curMo = "In4";
  1661. else if (moName.Contains("tmga") || displayName.Contains("tmga")) curMo = "TMG";
  1662. else if (moName.Contains("tmga_1") || displayName.Contains("tmga_1")) curMo = "TMG1";
  1663. else if (moName.Contains("tmga_2") || displayName.Contains("tmga_2")) curMo = "TMG2";
  1664. else if (moName.Contains("tmga_3") || displayName.Contains("tmga_3")) curMo = "TMG3";
  1665. else if (moName.Contains("tmga_4") || displayName.Contains("tmga_4")) curMo = "TMG4";
  1666. else if (moName.Contains("tega") || displayName.Contains("tega")) curMo = "TEG";
  1667. else if (moName.Contains("tega_1") || displayName.Contains("tega_1")) curMo = "TEG1";
  1668. else if (moName.Contains("tega_2") || displayName.Contains("tega_2")) curMo = "TEG2";
  1669. else if (moName.Contains("tega_3") || displayName.Contains("tega_3")) curMo = "TEG3";
  1670. else if (moName.Contains("tega_4") || displayName.Contains("tega_4")) curMo = "TEG4";
  1671. else if (moName.Contains("tmal") || displayName.Contains("tmal")) curMo = "TAl";
  1672. else if (moName.Contains("tmal_1") || displayName.Contains("tmal_1")) curMo = "TAl1";
  1673. else if (moName.Contains("tmal_2") || displayName.Contains("tmal_2")) curMo = "TAl2";
  1674. else if (moName.Contains("tmal_3") || displayName.Contains("tmal_3")) curMo = "TAl3";
  1675. else if (moName.Contains("tmal_4") || displayName.Contains("tmal_4")) curMo = "TAl4";
  1676. else if (moName.Contains("nh3source") || displayName.Contains("nh3source")) curMo = "NH3";
  1677. else if (moName.Contains("si")) curMo = "Si";
  1678. if (!string.IsNullOrEmpty(curMo))
  1679. {
  1680. if (string.IsNullOrEmpty(materialName))
  1681. materialName = curMo;
  1682. else
  1683. materialName += "|" + curMo;
  1684. }
  1685. }
  1686. }
  1687. if (materialRowId >= 0)
  1688. {
  1689. RecipeRows[materialRowId].RecipeItems[colId].Value = materialName;
  1690. RecipeRows[materialRowId].RecipeItems[colId].InvokePropertyChanged();
  1691. }
  1692. }
  1693. #endregion update material cell data
  1694. #region update column header
  1695. if (DataGridControl.Columns.Count - 1 == RecipeRows[0].RecipeItems.Count)
  1696. {
  1697. var redColHeader = (DataTemplate)DataGridControl.FindResource("columnRedTitleTemplate");
  1698. var blackColHeader = (DataTemplate)DataGridControl.FindResource("columnBlackTitleTemplate");
  1699. for (int j = 0; j < RecipeRows[0].RecipeItems.Count; j++)
  1700. {
  1701. DataGridControl.Columns[j + 1].Title = string.Format("{0}|{2}\r\n{1}", j + 1, RecipeRows[0].RecipeItems[j].Value, RecipeRows[2].RecipeItems[j].Value);
  1702. if (Errors.Find((o) => o.Item2 == j) != null)
  1703. DataGridControl.Columns[j + 1].TitleTemplate = redColHeader;
  1704. else
  1705. DataGridControl.Columns[j + 1].TitleTemplate = blackColHeader;
  1706. }
  1707. }
  1708. #endregion update column header
  1709. #region if running state, highlight current running step, move horizontal bar to current running step
  1710. if (CurrentRunningStepNo > 0 && DataGridControl.Columns.Count > 2)
  1711. {
  1712. for (int rowId = 0; rowId < RecipeRows.Count; rowId++)
  1713. {
  1714. for (int colId = 0; colId < RecipeRows[0].RecipeItems.Count; colId++)
  1715. {
  1716. var cell = RecipeRows[rowId].RecipeItems[colId];
  1717. if (colId + 1 == CurrentRunningStepNo)
  1718. {
  1719. cell.IsRunning = true;
  1720. }
  1721. else
  1722. {
  1723. cell.IsRunning = false;
  1724. }
  1725. cell.InvokePropertyChanged("IsRunning");
  1726. }
  1727. }
  1728. if (moving2RunningStepPosition)
  1729. {
  1730. Task.Factory.StartNew(() =>
  1731. {
  1732. System.Threading.Thread.Sleep(200);
  1733. DataGridControl.Dispatcher.Invoke(new Action(() =>
  1734. {
  1735. double singleWidth = DataGridControl.Columns[1].Width;
  1736. double horizontalOffset = (CurrentRunningStepNo - 2) * singleWidth;
  1737. if (DataGridControl.ScrollViewer != null)
  1738. {
  1739. if (horizontalOffset > DataGridControl.ScrollViewer.ScrollableWidth)
  1740. horizontalOffset = DataGridControl.ScrollViewer.ScrollableWidth;
  1741. if (horizontalOffset < 0)
  1742. horizontalOffset = 0;
  1743. DataGridControl.ScrollViewer.ScrollToHorizontalOffset(horizontalOffset);
  1744. }
  1745. }));
  1746. });
  1747. }
  1748. }
  1749. #endregion if running state, highlight current running step, move horizontal bar to current running step
  1750. //calc recipe time
  1751. CalcRecipeTime();
  1752. //invoke property
  1753. InvokePropertyChanged("Errors");
  1754. }
  1755. catch (Exception ex)
  1756. {
  1757. MessageBox.Show("工艺程序校验出错!\r\n\r\n" + ex.Message, "出错", MessageBoxButton.OK, MessageBoxImage.Error);
  1758. System.Diagnostics.Debug.WriteLine(ex.Message);
  1759. }
  1760. }
  1761. /// <summary>
  1762. /// reload datagrid content
  1763. /// </summary>
  1764. private void RefreshDataGrid()
  1765. {
  1766. try
  1767. {
  1768. //generate columns in Grid
  1769. DataGridControl.CurrentColumn = null;
  1770. if (DataGridControl.Columns.Count > 0)
  1771. DataGridControl.Columns.Clear();
  1772. var template = (DataTemplate)DataGridControl.FindResource("CustomTemplate");
  1773. var rowTemplate = (DataTemplate)DataGridControl.FindResource("RowHeadTemplate");
  1774. DataGridControl.Columns.Add(new Xceed.Wpf.DataGrid.Column()
  1775. {
  1776. Width = 140,
  1777. Title = " ",
  1778. FieldName = ".",
  1779. CellContentTemplate = rowTemplate
  1780. });
  1781. var cellEditor = DataGridControl.DefaultCellEditors[typeof(SmartCellData)];// DefaultCellEditorSelector.SelectCellEditor(typeof(SmartCellData));
  1782. for (int index = 0; index < RecipeRows[0].RecipeItems.Count; index++)
  1783. {
  1784. //var col = new Xceed.Wpf.DataGrid.Column();
  1785. DataGridControl.Columns.Add(new Xceed.Wpf.DataGrid.Column()
  1786. {
  1787. Title = string.Format("【{0}】\r\n{1}", index + 1, RecipeRows[0].RecipeItems[index].Value),
  1788. FieldName = string.Format("RecipeItems[{0}]", index),
  1789. CellContentTemplate = template,
  1790. AllowSort = false,
  1791. Width = 120,
  1792. MaxWidth = 120,
  1793. CellEditor = cellEditor
  1794. });
  1795. }
  1796. InvokePropertyChanged("RecipeRows");
  1797. InvokePropertyChanged("RecipeHead");
  1798. }
  1799. catch (Exception ex)
  1800. {
  1801. System.Diagnostics.Debug.WriteLine(ex.Message);
  1802. }
  1803. }
  1804. /// <summary>
  1805. /// calc recipe total time
  1806. /// </summary>
  1807. private void CalcRecipeTime()
  1808. {
  1809. int timeStepRowId = -1;
  1810. int loopStepRowId = -1;
  1811. for (int i = 0; i < RecipeRows.Count; i++)
  1812. {
  1813. if (RecipeRows[i].TechnicalName == "Time")
  1814. timeStepRowId = i;
  1815. if (RecipeRows[i].TechnicalName == "Loop")
  1816. loopStepRowId = i;
  1817. if (loopStepRowId != -1 && timeStepRowId != -1)
  1818. break;
  1819. }
  1820. TimeSpan tspan = new TimeSpan();
  1821. for (int stepNo = 0; stepNo < RecipeRows[timeStepRowId].RecipeItems.Count; stepNo++)
  1822. {
  1823. string loopStr = RecipeRows[loopStepRowId].RecipeItems[stepNo].Value;
  1824. bool isLoopStart = Regex.IsMatch(loopStr, @"^Loop\x20\d+$");
  1825. if (isLoopStart)
  1826. {
  1827. int loopNum = int.Parse(loopStr.ToLower().Replace("loop", "").Replace(" ", ""));
  1828. TimeSpan ts = new TimeSpan();
  1829. for (int innerStepNo = stepNo; innerStepNo < RecipeRows[timeStepRowId].RecipeItems.Count; innerStepNo++)
  1830. {
  1831. loopStr = RecipeRows[loopStepRowId].RecipeItems[innerStepNo].Value;
  1832. stepNo = innerStepNo;
  1833. string timeDuration = RecipeRows[timeStepRowId].RecipeItems[innerStepNo].Value;
  1834. string[] timeArr = timeDuration.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries);
  1835. if (timeArr.Length == 3)
  1836. {
  1837. int h, mi, s;
  1838. if (int.TryParse(timeArr[0], out h) && int.TryParse(timeArr[1], out mi) && int.TryParse(timeArr[2], out s))
  1839. {
  1840. var tt = new TimeSpan(h, mi, s);
  1841. ts += tt;
  1842. }
  1843. }
  1844. bool isLoopEnd = Regex.IsMatch(loopStr, @"^Loop End$");
  1845. if (isLoopEnd)
  1846. {
  1847. tspan += new TimeSpan(ts.Ticks * loopNum);
  1848. break;
  1849. }
  1850. }
  1851. }
  1852. else
  1853. {
  1854. string timeDuration = RecipeRows[timeStepRowId].RecipeItems[stepNo].Value;
  1855. string[] timeArr = timeDuration.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries);
  1856. if (timeArr.Length == 3)
  1857. {
  1858. int h, mi, s;
  1859. if (int.TryParse(timeArr[0], out h) && int.TryParse(timeArr[1], out mi) && int.TryParse(timeArr[2], out s))
  1860. {
  1861. var ts = new TimeSpan(h, mi, s);
  1862. tspan += ts;
  1863. }
  1864. }
  1865. }
  1866. }
  1867. RecipeInfo = string.Format("共{0}步,总时间{1}:{2}:{3}", RecipeRows[0].RecipeItems.Count, (int)tspan.TotalHours, tspan.Minutes.ToString("00"), tspan.Seconds.ToString("00"));
  1868. InvokePropertyChanged("RecipeInfo");
  1869. }
  1870. #region INotifyPropertyChanged
  1871. public event PropertyChangedEventHandler PropertyChanged;
  1872. public void InvokePropertyChanged(string propertyName)
  1873. {
  1874. if (PropertyChanged != null)
  1875. {
  1876. PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
  1877. }
  1878. }
  1879. #endregion INotifyPropertyChanged
  1880. }
  1881. public class RecipePredefine123
  1882. {
  1883. /// <summary>
  1884. /// 最大升温速度 C/sec
  1885. /// </summary>
  1886. public double MaxTempRampUpRate { get; set; }
  1887. /// <summary>
  1888. /// 最大降温速度 C/sec
  1889. /// </summary>
  1890. public double MaxTempRampDownRate { get; set; }
  1891. /// <summary>
  1892. /// 加热区允许的最大温差设定值 C
  1893. /// </summary>
  1894. public double MaxTempDT { get; set; }
  1895. /// <summary>
  1896. /// Heat Purge最小流量设定 sccm
  1897. /// </summary>
  1898. public double MinHeatPurge { get; set; }
  1899. /// <summary>
  1900. /// Spindle最低转速 rpm
  1901. /// </summary>
  1902. public double MinSpindleSpeed { get; set; }
  1903. /// <summary>
  1904. /// 腔体压力允许最低设定值 mbar
  1905. /// </summary>
  1906. public double MinPressureSetpoint { get; set; }
  1907. /// <summary>
  1908. /// 最大压力伺服速度 mbar/sec
  1909. /// </summary>
  1910. public double MaxPressRampRate { get; set; }
  1911. /// <summary>
  1912. /// 最大转盘旋转加速度 rpm/sec
  1913. /// </summary>
  1914. public double MaxSpindleRampRate { get; set; }
  1915. /// <summary>
  1916. /// 最大温度设定值
  1917. /// </summary>
  1918. public double MaxTempSetpoint { get; set; }
  1919. /// <summary>
  1920. /// 最大电流设定值
  1921. /// </summary>
  1922. public double AZoneMaxCurrentSetpoint { get; set; }
  1923. public double BZoneMaxCurrentSetpoint { get; set; }
  1924. public double CZoneMaxCurrentSetpoint { get; set; }
  1925. public double DZoneMaxCurrentSetpoint { get; set; }
  1926. }
  1927. public class RecipeRow
  1928. {
  1929. private ObservableCollection<SmartCellData> _recipeItems = new ObservableCollection<SmartCellData>();
  1930. public RecipeRow(params SmartCellData[] vars)
  1931. {
  1932. foreach (var var in vars)
  1933. _recipeItems.Add(var);
  1934. }
  1935. public string CatalogName { get; set; }
  1936. public string FriendlyName { get; set; }
  1937. public string TechnicalName { get; set; }
  1938. public ObservableCollection<SmartCellData> RecipeItems
  1939. {
  1940. get { return _recipeItems; }
  1941. set { _recipeItems = value; }
  1942. }
  1943. }
  1944. /// <summary>
  1945. /// Recipe head
  1946. /// </summary>
  1947. public class RecipeHead
  1948. {
  1949. public string RecipeVariation { get; set; }
  1950. public string CreationTime { get; set; }
  1951. public string LastRevisionTime { get; set; }
  1952. public string CreatedBy { get; set; }
  1953. public string LastModifiedBy { get; set; }
  1954. public string PressureMode { get; set; }
  1955. public string Description { get; set; }
  1956. public string BasePressure
  1957. {
  1958. get; set;
  1959. }
  1960. public string PumpDownLimit
  1961. {
  1962. get; set;
  1963. }
  1964. public string ElectrodeTemp
  1965. {
  1966. get; set;
  1967. }
  1968. public string PurgeActive
  1969. {
  1970. get; set;
  1971. }
  1972. public string Barcode
  1973. {
  1974. get; set;
  1975. }
  1976. }
  1977. }