RecipeEditorControlViewModel.cs 107 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277
  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.SubstrateTemp))
  637. {
  638. rootNode.SetAttribute("SubstrateTemp", RecipeHead.SubstrateTemp);
  639. }
  640. if (!string.IsNullOrEmpty(RecipeHead.PinStateAfterVent))
  641. {
  642. rootNode.SetAttribute("PinStateAfterVent", RecipeHead.PinStateAfterVent);
  643. }
  644. if (!string.IsNullOrEmpty(RecipeHead.PumpingPinState))
  645. {
  646. rootNode.SetAttribute("PumpingPinState", RecipeHead.PumpingPinState);
  647. }
  648. if (!string.IsNullOrEmpty(RecipeHead.PumpDownLimit))
  649. {
  650. rootNode.SetAttribute("PumpDownLimit", RecipeHead.PumpDownLimit);
  651. }
  652. if (!string.IsNullOrEmpty(RecipeHead.PinDownPressure))
  653. {
  654. rootNode.SetAttribute("PinDownPressure", RecipeHead.PinDownPressure);
  655. }
  656. if (!string.IsNullOrEmpty(RecipeHead.PurgeActive))
  657. {
  658. rootNode.SetAttribute("PurgeActive", RecipeHead.PurgeActive);
  659. }
  660. rootNode.SetAttribute("Barcode", RecipeHead.Barcode);
  661. rootNode.SetAttribute("Description", RecipeHead.Description);
  662. doc.AppendChild(rootNode);
  663. for (int stepIndex/* 0-> */ = 0; stepIndex < RecipeRows[0].RecipeItems.Count; stepIndex++)
  664. {
  665. var stepNode = doc.CreateElement("Step");
  666. rootNode.AppendChild(stepNode);
  667. foreach (var module in _recipeSavingFormat)
  668. {
  669. var moduleName = module.Key;
  670. XmlElement subNode = stepNode;
  671. if (!string.IsNullOrEmpty(moduleName))
  672. {
  673. string[] pathArr = moduleName.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
  674. for (int i = 0; i < pathArr.Length; i++)
  675. {
  676. var snd = subNode.SelectSingleNode(pathArr[i]) as XmlElement;
  677. if (snd == null)
  678. {
  679. var nd = doc.CreateElement(pathArr[i]);
  680. subNode.AppendChild(nd);
  681. subNode = nd;
  682. }
  683. else
  684. {
  685. subNode = snd;
  686. }
  687. }
  688. }
  689. foreach (var controlName in module.Value)
  690. {
  691. if (controlName == "StepNo")
  692. {
  693. subNode.SetAttribute(controlName, string.Format("第{0}步", stepIndex + 1));
  694. }
  695. else
  696. {
  697. var recipeRow = RecipeRows.First((o) => o.TechnicalName == controlName);
  698. if (recipeRow == null) continue;
  699. /*to compatiable with old recipe editor, always fill 'black space' to loop step*/
  700. if (controlName == "Loop" && string.IsNullOrEmpty(recipeRow.RecipeItems[stepIndex].Value))
  701. subNode.SetAttribute(controlName, " ");
  702. else
  703. {
  704. subNode.SetAttribute(controlName, recipeRow.RecipeItems[stepIndex].Value);
  705. //bool isJump = recipeRow.RecipeItems[stepIndex].IsJump;
  706. //if (isJump)
  707. //{
  708. // string deviceType = recipeRow.RecipeItems[stepIndex].RecipeVariableDefine.DeviceType;
  709. // if (deviceType == "MFC" || deviceType == "PC")
  710. // subNode.SetAttribute(controlName + ".IsJump", isJump.ToString());
  711. //}
  712. }
  713. }
  714. }
  715. }
  716. }
  717. return doc.OuterXml;
  718. }
  719. /// <summary>
  720. /// expand groups
  721. /// </summary>
  722. private void ExpandGroups()
  723. {
  724. try
  725. {
  726. foreach (CollectionViewGroup item in DataGridControl.Items.Groups)
  727. {
  728. DataGridControl.ExpandGroup(item);
  729. }
  730. }
  731. catch (Exception ex)
  732. {
  733. System.Diagnostics.Debug.WriteLine(ex.Message);
  734. }
  735. }
  736. /// <summary>
  737. /// collapse groups
  738. /// </summary>
  739. private void CollapseGroups()
  740. {
  741. try
  742. {
  743. foreach (CollectionViewGroup item in DataGridControl.Items.Groups)
  744. {
  745. DataGridControl.CollapseGroup(item);
  746. }
  747. }
  748. catch (Exception ex)
  749. {
  750. System.Diagnostics.Debug.WriteLine(ex.Message);
  751. }
  752. }
  753. /// <summary>
  754. /// right click context menu
  755. /// </summary>
  756. private void RightClickAction()
  757. {
  758. DataGridControl.ContextMenu = null;
  759. //get selected column information
  760. List<int> selectedColumns = new List<int>();
  761. foreach (var item in DataGridControl.SelectedCellRanges)
  762. {
  763. bool dir = item.ColumnRange.StartIndex <= item.ColumnRange.EndIndex;
  764. if (dir)
  765. {
  766. for (int i = item.ColumnRange.StartIndex; i <= item.ColumnRange.EndIndex; i++)
  767. {
  768. if (i > 0)
  769. if (!selectedColumns.Contains(i)) selectedColumns.Add(i);
  770. }
  771. }
  772. else
  773. {
  774. for (int i = item.ColumnRange.StartIndex; i >= item.ColumnRange.EndIndex; i--)
  775. {
  776. if (i > 0)
  777. if (!selectedColumns.Contains(i)) selectedColumns.Add(i);
  778. }
  779. }
  780. }
  781. selectedColumns.Sort();
  782. //debug only
  783. /*
  784. string s = "";
  785. foreach (var item in selectedColumns)
  786. {
  787. s += "," + item;
  788. }
  789. MessageBox.Show(s);
  790. * */
  791. //generate context menu
  792. ContextMenu cms = new ContextMenu();
  793. if (selectedColumns.Count > 0)
  794. {
  795. string colStrings = "";
  796. foreach (var item in selectedColumns)
  797. {
  798. if (string.IsNullOrEmpty(colStrings))
  799. colStrings = item.ToString();
  800. else
  801. colStrings += "," + item.ToString();
  802. }
  803. MenuItem mi;
  804. cms.Items.Add(new MenuItem() { Header = string.Format(" 当前选中第{0}步", colStrings), FontFamily = new FontFamily("Arial,SimSun"), IsEnabled = false, Background = Brushes.Gray, Foreground = Brushes.White });
  805. //copy
  806. mi = new MenuItem() { Header = " 复制", FontFamily = new FontFamily("Arial,SimSun"), Tag = selectedColumns.ToList() };
  807. mi.Click += (s, e) =>
  808. {
  809. try
  810. {
  811. var list = (s as MenuItem).Tag as List<int>;
  812. _copiedColumnDatas.Clear();
  813. foreach (var colId in list)
  814. {
  815. _copiedColumnDatas.Add(colId/*index from 1*/, new List<SmartCellData>());
  816. for (int i = 0; i < RecipeRows.Count; i++)
  817. {
  818. var oldCellData = RecipeRows[i].RecipeItems[colId - 1];
  819. var newCellData = new SmartCellData() { Value = oldCellData.Value, RecipeVariableDefine = oldCellData.RecipeVariableDefine };
  820. _copiedColumnDatas[colId].Add(newCellData);
  821. }
  822. }
  823. }
  824. catch (Exception ex)
  825. {
  826. System.Diagnostics.Debug.WriteLine(ex.Message);
  827. }
  828. };
  829. cms.Items.Add(mi);
  830. if (selectedColumns.Count < RecipeRows[0].RecipeItems.Count)
  831. {
  832. mi = new MenuItem() { Header = " 剪切", FontFamily = new FontFamily("Arial,SimSun"), Tag = selectedColumns.ToList() };
  833. mi.Click += (s, e) =>
  834. {
  835. try
  836. {
  837. AddUndoHistory("剪切", CloneRecipeRowData(RecipeRows));
  838. var list = (s as MenuItem).Tag as List<int>;
  839. _copiedColumnDatas.Clear();
  840. foreach (var colId in list)
  841. {
  842. _copiedColumnDatas.Add(colId/*index from 1*/, new List<SmartCellData>());
  843. for (int i = 0; i < RecipeRows.Count; i++)
  844. {
  845. var oldCellData = RecipeRows[i].RecipeItems[colId - 1];
  846. var newCellData = new SmartCellData() { Value = oldCellData.Value, RecipeVariableDefine = oldCellData.RecipeVariableDefine };
  847. _copiedColumnDatas[colId].Add(newCellData);
  848. }
  849. }
  850. foreach (var item in RecipeRows)
  851. {
  852. var collection = new ObservableCollection<SmartCellData>();
  853. for (int index = 0; index < item.RecipeItems.Count; index++)
  854. {
  855. if (list.Contains(index + 1))
  856. continue;
  857. collection.Add(item.RecipeItems[index]);
  858. }
  859. item.RecipeItems = collection;
  860. }
  861. RefreshDataGrid();
  862. RefreshCellsDisplay(false);
  863. }
  864. catch (Exception ex)
  865. {
  866. System.Diagnostics.Debug.WriteLine(ex.Message);
  867. }
  868. };
  869. cms.Items.Add(mi);
  870. mi = new MenuItem() { Header = " 删除", FontFamily = new FontFamily("Arial,SimSun"), Tag = selectedColumns.ToList() };
  871. mi.Click += (s, e) =>
  872. {
  873. try
  874. {
  875. AddUndoHistory("删除", CloneRecipeRowData(RecipeRows));
  876. var list = (s as MenuItem).Tag as List<int>;
  877. foreach (var item in RecipeRows)
  878. {
  879. var collection = new ObservableCollection<SmartCellData>();
  880. for (int index = 0; index < item.RecipeItems.Count; index++)
  881. {
  882. if (list.Contains(index + 1))
  883. continue;
  884. collection.Add(item.RecipeItems[index]);
  885. }
  886. item.RecipeItems = collection;
  887. }
  888. RefreshDataGrid();
  889. RefreshCellsDisplay(false);
  890. }
  891. catch (Exception ex)
  892. {
  893. System.Diagnostics.Debug.WriteLine(ex.Message);
  894. }
  895. };
  896. cms.Items.Add(mi);
  897. }
  898. if (selectedColumns.Count == 1 && _copiedColumnDatas.Count > 0)
  899. {
  900. mi = new MenuItem() { Header = string.Format(" 插入第{0}步后", selectedColumns[0]/*, _copiedColumnDatas.Count*/), FontFamily = new FontFamily("Arial,SimSun"), Tag = selectedColumns[0] };
  901. mi.Click += (s, e) =>
  902. {
  903. try
  904. {
  905. AddUndoHistory("插入", CloneRecipeRowData(RecipeRows));
  906. int insertColId = (int)(s as MenuItem).Tag;
  907. for (int rowIndex = 0; rowIndex < RecipeRows.Count; rowIndex++)
  908. {
  909. var collection = new ObservableCollection<SmartCellData>();
  910. for (int index = 0; index < insertColId; index++)
  911. {
  912. collection.Add(RecipeRows[rowIndex].RecipeItems[index]);
  913. }
  914. foreach (var col in _copiedColumnDatas)
  915. {
  916. collection.Add(new SmartCellData() { Value = col.Value[rowIndex].Value, RecipeVariableDefine = col.Value[rowIndex].RecipeVariableDefine });
  917. }
  918. for (int index = insertColId; index < RecipeRows[rowIndex].RecipeItems.Count; index++)
  919. {
  920. collection.Add(RecipeRows[rowIndex].RecipeItems[index]);
  921. }
  922. RecipeRows[rowIndex].RecipeItems = collection;
  923. }
  924. RefreshDataGrid();
  925. RefreshCellsDisplay(false);
  926. }
  927. catch (Exception ex)
  928. {
  929. System.Diagnostics.Debug.WriteLine(ex.Message);
  930. }
  931. };
  932. cms.Items.Add(mi);
  933. }
  934. }
  935. //show context menu
  936. DataGridControl.ContextMenu = cms;
  937. cms.Visibility = Visibility.Visible;
  938. }
  939. /// <summary>
  940. /// Parse recipe content with recipe format
  941. /// </summary>
  942. /// <param name="recipeFormat"></param>
  943. /// <param name="recipeContent"></param>
  944. /// <param name="selectedStepNo"></param>
  945. public void LoadRecipe(string recipeFormat, string recipeContent, int selectedStepNo = -1)
  946. {
  947. CurrentRunningStepNo = selectedStepNo;
  948. IsHideSameContent = false;
  949. IsRecipeModified = false;
  950. RecipeHead = new RecipeEditor.RecipeHead();
  951. DataGridControl.ContextMenu = null;
  952. RecipeInfo = "";
  953. IsBusy = true;
  954. InvokePropertyChanged("IsBusy");
  955. UndoList.Clear();
  956. RedoList.Clear();
  957. InvokePropertyChanged("UndoList");
  958. InvokePropertyChanged("RedoList");
  959. InvokePropertyChanged("IsUndoEnabled");
  960. InvokePropertyChanged("IsRedoEnabled");
  961. try
  962. {
  963. RecipeRows = new ObservableCollection<RecipeRow>();
  964. _recipeReadingFormat = new Dictionary<string, Dictionary<string, List<RecipeVariableDefine>>>();
  965. _recipeSavingFormat = new Dictionary<string, List<string>>();
  966. //parse recipe format
  967. XmlDocument formatXml = new XmlDocument();
  968. formatXml.LoadXml(recipeFormat);
  969. _currentRecipeFormatContent = formatXml.OuterXml;
  970. //reading recipe variation
  971. string recipeVariationName = formatXml.SelectSingleNode("TableRecipeFormat").Attributes["RecipeVersion"].Value;
  972. if (String.Compare(recipeVariationName, _currentRecipeVariationName) != 0)
  973. {
  974. //if variation name is different from previous loaded recipe -> clear all previous copied recipe columns
  975. _copiedColumnDatas.Clear();
  976. }
  977. _currentRecipeVariationName = recipeVariationName;
  978. //reading recipe validation releated parameters
  979. _preDefinedRecipeVars = new Dictionary<string, string>();
  980. foreach (XmlElement nd in formatXml.SelectNodes("/TableRecipeFormat/Validation/Predefine/Item"))
  981. {
  982. _preDefinedRecipeVars.Add(nd.Attributes["VarName"].Value, nd.Attributes["Value"].Value);
  983. }
  984. //reading check variables
  985. _checkVariables = new List<string>();
  986. foreach (XmlElement nd in formatXml.SelectNodes("/TableRecipeFormat/Validation/CheckVariable/Var"))
  987. {
  988. string varName = nd.Attributes["Name"].Value;
  989. _checkVariables.Add(varName);
  990. }
  991. //reading validation rules
  992. _validationRules = new List<Tuple<string, string, string>>();
  993. foreach (XmlElement nd in formatXml.SelectNodes("/TableRecipeFormat/Validation/Restriction/Rule"))
  994. {
  995. string varName = nd.Attributes["VarName"].Value;
  996. string checkCondition = nd.Attributes["CheckCondition"].Value.Replace("&lt;", "<").Replace("&gt;", ">");
  997. string message = nd.Attributes["Message"].Value.Replace("'", "\"");
  998. _validationRules.Add(new Tuple<string, string, string>(varName, checkCondition, message));
  999. }
  1000. //parsing recipe format xml file
  1001. foreach (XmlElement catalogNode in formatXml.SelectNodes("/TableRecipeFormat/Catalog"))
  1002. {
  1003. string catalogName = catalogNode.Attributes["DisplayName"].Value;
  1004. _recipeReadingFormat.Add(catalogName, new Dictionary<string, List<RecipeVariableDefine>>());
  1005. foreach (XmlElement groupNode in catalogNode.SelectNodes("Group"))
  1006. {
  1007. string groupName = groupNode.Attributes["DisplayName"].Value;
  1008. _recipeReadingFormat[catalogName].Add(groupName, new List<RecipeVariableDefine>());
  1009. foreach (XmlElement stepNode in groupNode.SelectNodes("Step"))
  1010. {
  1011. string stepModuleName = stepNode.Attributes["ModuleName"].Value;
  1012. string stepDeviceType = stepNode.Attributes["DeviceType"].Value;
  1013. string stepDisplayName = stepNode.Attributes["DisplayName"].Value;
  1014. string stepControlName = stepNode.Attributes["ControlName"].Value;
  1015. string stepInputType = stepNode.Attributes["InputType"].Value;
  1016. string stepDescription = stepNode.HasAttribute("Desc") ? stepNode.Attributes["Desc"].Value : "";
  1017. double stepMin = double.Parse(stepNode.HasAttribute("Min") ? stepNode.Attributes["Min"].Value : "0");
  1018. double stepMax = double.Parse(stepNode.HasAttribute("Max") ? stepNode.Attributes["Max"].Value : "0");
  1019. var selectionList = new List<Tuple<string, string>>();
  1020. foreach (XmlElement selectionNode in stepNode.SelectNodes("Item"))
  1021. {
  1022. selectionList.Add(new Tuple<string, string>(selectionNode.Attributes["ControlName"].Value, selectionNode.Attributes["DisplayName"].Value));
  1023. }
  1024. if (!_recipeSavingFormat.ContainsKey(stepModuleName)) _recipeSavingFormat.Add(stepModuleName, new List<string>());
  1025. _recipeSavingFormat[stepModuleName].Add(stepControlName);
  1026. if (stepControlName == "StepNo")
  1027. continue;
  1028. _recipeReadingFormat[catalogName][groupName].Add(new RecipeVariableDefine()
  1029. {
  1030. CellType = (CellType)Enum.Parse(typeof(CellType), stepInputType),
  1031. Description = stepDescription,
  1032. DeviceType = stepDeviceType,
  1033. DropdownItemList = selectionList,
  1034. MaxValue = stepMax,
  1035. //MinValue = stepDeviceType.Equals("MFC",StringComparison.InvariantCultureIgnoreCase)? stepMax*2.0/100: stepMin,
  1036. MinValue = stepMin,
  1037. GroupName = groupName,
  1038. CatalogName = catalogName,
  1039. TechnicalName = stepControlName,
  1040. FriendlyName = stepDisplayName
  1041. });
  1042. }
  1043. }
  1044. }
  1045. //parse recipe content
  1046. XmlDocument contentXml = new XmlDocument();
  1047. contentXml.LoadXml(recipeContent);
  1048. contentXml.DocumentElement.SetAttribute("RecipeVersion", _currentRecipeVariationName);
  1049. //read recipe head
  1050. //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"
  1051. RecipeHead.CreatedBy = contentXml.DocumentElement.HasAttribute("CreatedBy") ? contentXml.DocumentElement.Attributes["CreatedBy"].Value : "(无)";
  1052. RecipeHead.CreationTime = contentXml.DocumentElement.HasAttribute("CreationTime") ? contentXml.DocumentElement.Attributes["CreationTime"].Value : "(无)";
  1053. RecipeHead.LastModifiedBy = contentXml.DocumentElement.HasAttribute("LastRevisedBy") ? contentXml.DocumentElement.Attributes["LastRevisedBy"].Value : "(无)";
  1054. RecipeHead.LastRevisionTime = contentXml.DocumentElement.HasAttribute("LastRevisionTime") ? contentXml.DocumentElement.Attributes["LastRevisionTime"].Value : "(无)";
  1055. if (contentXml.DocumentElement.HasAttribute("PressureMode"))
  1056. {
  1057. RecipeHead.PressureMode = contentXml.DocumentElement.Attributes["PressureMode"].Value;
  1058. }
  1059. if (contentXml.DocumentElement.HasAttribute("BasePressure"))
  1060. {
  1061. RecipeHead.BasePressure = contentXml.DocumentElement.Attributes["BasePressure"].Value;
  1062. }
  1063. if (contentXml.DocumentElement.HasAttribute("PumpDownLimit"))
  1064. {
  1065. RecipeHead.PumpDownLimit = contentXml.DocumentElement.Attributes["PumpDownLimit"].Value;
  1066. }
  1067. if (contentXml.DocumentElement.HasAttribute("SubstrateTemp"))
  1068. {
  1069. RecipeHead.SubstrateTemp = contentXml.DocumentElement.Attributes["SubstrateTemp"].Value;
  1070. }
  1071. if (contentXml.DocumentElement.HasAttribute("PinStateAfterVent"))
  1072. {
  1073. RecipeHead.PinStateAfterVent = contentXml.DocumentElement.Attributes["PinStateAfterVent"].Value;
  1074. }
  1075. if (contentXml.DocumentElement.HasAttribute("PumpingPinState"))
  1076. {
  1077. RecipeHead.PumpingPinState = contentXml.DocumentElement.Attributes["PumpingPinState"].Value;
  1078. }
  1079. if (contentXml.DocumentElement.HasAttribute("PinDownPressure"))
  1080. {
  1081. RecipeHead.PinDownPressure = contentXml.DocumentElement.Attributes["PinDownPressure"].Value;
  1082. }
  1083. if (contentXml.DocumentElement.HasAttribute("PurgeActive"))
  1084. {
  1085. RecipeHead.PurgeActive = contentXml.DocumentElement.Attributes["PurgeActive"].Value;
  1086. }
  1087. if (contentXml.DocumentElement.HasAttribute("Barcode"))
  1088. {
  1089. RecipeHead.Barcode = contentXml.DocumentElement.Attributes["Barcode"].Value;
  1090. }
  1091. RecipeHead.RecipeVariation = contentXml.DocumentElement.HasAttribute("RecipeVersion") ? contentXml.DocumentElement.Attributes["RecipeVersion"].Value : "(NULL)";
  1092. RecipeHead.Description = contentXml.DocumentElement.HasAttribute("Description") ? contentXml.DocumentElement.Attributes["Description"].Value : "(NULL)";
  1093. var allRecipeItems = new List<Dictionary<string, string>>();
  1094. foreach (XmlElement stepNode in contentXml.SelectNodes("/TableRecipeData/Step"))
  1095. {
  1096. var stepDic = new Dictionary<string, string>();
  1097. allRecipeItems.Add(stepDic);
  1098. foreach (XmlAttribute att in stepNode.Attributes)
  1099. {
  1100. stepDic.Add(att.Name, att.Value);
  1101. }
  1102. foreach (XmlElement innerStep in stepNode.ChildNodes)
  1103. {
  1104. foreach (XmlAttribute att in innerStep.Attributes)
  1105. {
  1106. stepDic.Add(att.Name, att.Value);
  1107. }
  1108. foreach (XmlElement innerInnerStep in innerStep.ChildNodes)
  1109. {
  1110. foreach (XmlAttribute att in innerInnerStep.Attributes)
  1111. {
  1112. stepDic.Add(att.Name, att.Value);
  1113. }
  1114. }
  1115. }
  1116. }
  1117. //generate view model
  1118. RowVarNameDic = new Dictionary<string, int>();
  1119. int rowIndex = 0;
  1120. foreach (var catalog in _recipeReadingFormat.Keys)
  1121. {
  1122. foreach (var group in _recipeReadingFormat[catalog].Keys)
  1123. {
  1124. foreach (var var1 in _recipeReadingFormat[catalog][group])
  1125. {
  1126. var singleRow = new RecipeRow() { CatalogName = catalog, FriendlyName = /*group + */var1.FriendlyName, TechnicalName = var1.TechnicalName };
  1127. for (int stepNo = 0; stepNo < allRecipeItems.Count; stepNo++)
  1128. {
  1129. var stepCell = new SmartCellData() { RecipeVariableDefine = var1 };
  1130. if (allRecipeItems[stepNo].ContainsKey(var1.TechnicalName))
  1131. {
  1132. stepCell.Value = allRecipeItems[stepNo][var1.TechnicalName];
  1133. //stepCell.ShowsJumpControl = false;
  1134. //if (var1.CellType == CellType.NumInput)
  1135. //{
  1136. // if (var1.DeviceType == "MFC" || var1.DeviceType == "PC")
  1137. // {
  1138. // string jumpString = var1.TechnicalName + ".IsJump";
  1139. // stepCell.IsJump = allRecipeItems[stepNo].ContainsKey(jumpString) ? bool.Parse(allRecipeItems[stepNo][jumpString]) : false;
  1140. // stepCell.ShowsJumpControl = true;
  1141. // }
  1142. //}
  1143. }
  1144. else
  1145. stepCell.Value = "n/a";
  1146. singleRow.RecipeItems.Add(stepCell);
  1147. }
  1148. RecipeRows.Add(singleRow);
  1149. RowVarNameDic.Add(var1.TechnicalName, rowIndex++);
  1150. }
  1151. }
  1152. }
  1153. //refresh datagrid
  1154. RefreshDataGrid();
  1155. //refresh recipe information
  1156. RefreshCellsDisplay();
  1157. if (OnLoadRecipeContent != null)
  1158. OnLoadRecipeContent.Invoke(recipeContent, null);
  1159. }
  1160. catch (Exception ex)
  1161. {
  1162. System.Diagnostics.Debug.WriteLine(ex.Message);
  1163. //LOG.Write("", ex);
  1164. }
  1165. IsBusy = false;
  1166. InvokePropertyChanged("IsBusy");
  1167. }
  1168. /// <summary>
  1169. /// 检查变量ramp rate
  1170. /// </summary>
  1171. /// <param name="stepNo"></param>
  1172. /// <param name="rampEnable"></param>
  1173. /// <param name="varName"></param>
  1174. /// <param name="rampTime"></param>
  1175. /// <param name="maxRampUpRate"></param>
  1176. /// <param name="maxRampDownRate"></param>
  1177. /// <returns>False:check ok, True: check failed</returns>
  1178. public bool CheckRampRate(int stepNo, string rampEnable, string varName, string rampTime, double maxRampUpRate, double maxRampDownRate)
  1179. {
  1180. try
  1181. {
  1182. if (stepNo <= 0) return false;
  1183. int rowIndex = RowVarNameDic[varName];
  1184. double currentValue = double.Parse(RecipeRows[rowIndex].RecipeItems[stepNo].Value);
  1185. //if (varName == "AZone.Setpoint" || varName == "BZone.Setpoint" || varName == "CZone.Setpoint" || varName == "DZone.Setpoint")
  1186. //{
  1187. // int heatControlModeIndex = RowVarNameDic["Heater.Mode"];
  1188. // string curStepHeatCtrlMode = RecipeRows[heatControlModeIndex].RecipeItems[stepNo].Value;
  1189. // string lastStepHeatCtrlMode = RecipeRows[heatControlModeIndex].RecipeItems[stepNo - 1].Value;
  1190. // if (curStepHeatCtrlMode != lastStepHeatCtrlMode)
  1191. // {
  1192. // if (!(lastStepHeatCtrlMode.Equals("CurrentControl") && curStepHeatCtrlMode.Equals("PyroTempControl")))
  1193. // return false;
  1194. // int endbyIndex = RowVarNameDic["EndBy"];
  1195. // int endValueIndex = RowVarNameDic["EndValue"];
  1196. // string endby = RecipeRows[endbyIndex].RecipeItems[stepNo - 1].Value;
  1197. // EndByCondition endbyEnum;
  1198. // if (!Enum.TryParse(endby, out endbyEnum)) return false;
  1199. // if (endbyEnum != EndByCondition.PmTempGt && endbyEnum != EndByCondition.PmTempLt) return false;
  1200. // string end = RecipeRows[endValueIndex].RecipeItems[stepNo - 1].Value;
  1201. // double endValue;
  1202. // if (!double.TryParse(end, out endValue)) return false;
  1203. // return CheckRampRate(rampEnable, rampTime, maxRampUpRate, maxRampDownRate, endValue, currentValue);
  1204. // }
  1205. //}
  1206. double prevValue = double.Parse(RecipeRows[rowIndex].RecipeItems[stepNo - 1].Value);
  1207. return CheckRampRate(rampEnable, rampTime, maxRampUpRate, maxRampDownRate, prevValue, currentValue);
  1208. }
  1209. catch (Exception ex)
  1210. {
  1211. System.Diagnostics.Debug.WriteLine(ex.Message);
  1212. return true;
  1213. }
  1214. }
  1215. bool CheckRampRate(string rampEnable, string rampTime, double maxRampUpRate, double maxRampDownRate, double prevValue, double currentValue)
  1216. {
  1217. bool isRampEnable = bool.Parse(rampEnable);
  1218. //string[] timeStr = rampTime.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries);
  1219. //string tt = string.Join(":", timeStr);
  1220. TimeSpan timeSpan;
  1221. TimeSpan.TryParse(rampTime, out timeSpan);
  1222. double totalTimeSec = timeSpan.TotalSeconds;
  1223. double diff = currentValue - prevValue;
  1224. if (!isRampEnable || totalTimeSec <= 0)
  1225. {
  1226. if (diff != 0) return true;
  1227. return false;
  1228. }
  1229. else
  1230. {
  1231. double rampRate = diff / totalTimeSec;
  1232. return (rampRate > 0 && rampRate >= maxRampUpRate) || (rampRate < 0 && rampRate <= -maxRampDownRate);
  1233. }
  1234. }
  1235. /// <summary>
  1236. /// Refresh datagrid cell data display
  1237. /// </summary>
  1238. /// <param name="moving2RunningStepPosition">True: moving to current running step position</param>
  1239. public void RefreshCellsDisplay(bool moving2RunningStepPosition = true)
  1240. {
  1241. try
  1242. {
  1243. if (RecipeRows == null || RecipeRows.Count < 2)
  1244. return;
  1245. Errors = new List<Tuple<int, int, string, string>>();
  1246. Dictionary<int, string> dicEndby = new Dictionary<int, string>();
  1247. Dictionary<int, string> dicPressureMode = new Dictionary<int, string>();
  1248. Dictionary<int, string> dicRfMode = new Dictionary<int, string>();
  1249. Dictionary<int, string> dicRfMatchProcessMode = new Dictionary<int, string>();
  1250. Dictionary<int, string> dicSetMatchPositionC1 = new Dictionary<int, string>();
  1251. Dictionary<int, string> dicSetMatchPositionC2 = new Dictionary<int, string>();
  1252. for (int i = 0; i < RecipeRows.Count; i++)
  1253. {
  1254. for (int j = 0; j < RecipeRows[i].RecipeItems.Count; j++)
  1255. {
  1256. var cell = RecipeRows[i].RecipeItems[j];
  1257. cell.RowIndex = i;
  1258. cell.ColIndex = j;
  1259. cell.ErrInfo = string.Empty;
  1260. bool logicEnable = true;
  1261. if (cell.RecipeVariableDefine.TechnicalName == "EndBy")
  1262. dicEndby[j] = cell.Value;
  1263. if (cell.RecipeVariableDefine.TechnicalName == "ThrottleValve.SetMode")
  1264. {
  1265. dicPressureMode[j] = cell.Value;
  1266. }
  1267. if (cell.RecipeVariableDefine.TechnicalName == "PressureControl.SetTVMode")
  1268. {
  1269. dicPressureMode[j] = cell.Value;
  1270. }
  1271. if (cell.RecipeVariableDefine.TechnicalName == "Rf.SetMode")
  1272. dicRfMode[j] = cell.Value;
  1273. if (cell.RecipeVariableDefine.TechnicalName == "Match.SetMatchProcessMode")
  1274. dicRfMatchProcessMode[j] = cell.Value;
  1275. if (cell.RecipeVariableDefine.TechnicalName == "Match.SetMatchPositionC1")
  1276. dicSetMatchPositionC1[j] = cell.Value;
  1277. if (cell.RecipeVariableDefine.TechnicalName == "Match.SetMatchPositionC2")
  1278. dicSetMatchPositionC2[j] = cell.Value;
  1279. if (cell.RecipeVariableDefine.TechnicalName == "Time")
  1280. {
  1281. logicEnable = dicEndby.ContainsKey(j) && (dicEndby[j] == "EndByStepTime" || dicEndby[j] == "EndByHeatUp");
  1282. }
  1283. if (cell.RecipeVariableDefine.TechnicalName == "ThrottleValve.SetPosition")
  1284. {
  1285. logicEnable = dicPressureMode.ContainsKey(j) && dicPressureMode[j] == "TVPositionCtrl";
  1286. }
  1287. if (cell.RecipeVariableDefine.TechnicalName == "ThrottleValve.SetPressure")
  1288. {
  1289. logicEnable = dicPressureMode.ContainsKey(j) && dicPressureMode[j] == "TVPressureCtrl";
  1290. }
  1291. if (cell.RecipeVariableDefine.TechnicalName == "PressureControl.SetTVPosition")
  1292. {
  1293. logicEnable = dicPressureMode.ContainsKey(j) && dicPressureMode[j] == "TVPositionCtrl";
  1294. }
  1295. if (cell.RecipeVariableDefine.TechnicalName == "PressureControl.SetTVPressure")
  1296. {
  1297. logicEnable = dicPressureMode.ContainsKey(j) && dicPressureMode[j] == "TVPressureCtrl";
  1298. }
  1299. if (cell.RecipeVariableDefine.TechnicalName == "Rf.SetPulsingFrequency")
  1300. {
  1301. logicEnable = dicRfMode.ContainsKey(j) && dicRfMode[j] == "PulsingMode";
  1302. }
  1303. if (cell.RecipeVariableDefine.TechnicalName == "Rf.SetPulsingDuty")
  1304. {
  1305. logicEnable = dicRfMode.ContainsKey(j) && dicRfMode[j] == "PulsingMode";
  1306. }
  1307. if (cell.RecipeVariableDefine.TechnicalName == "Rf.SetPowerOnTime")
  1308. {
  1309. logicEnable = dicEndby.ContainsKey(j) && dicEndby[j] == "EndByRfTime";
  1310. }
  1311. if (cell.RecipeVariableDefine.TechnicalName == "Match.SetMatchProcessMode")
  1312. {
  1313. logicEnable = dicRfMatchProcessMode.ContainsKey(j);// && dicRfMatchProcessMode[j] == "TritonPresetMode";
  1314. }
  1315. if (cell.RecipeVariableDefine.TechnicalName == "Match.SetMatchPositionC1")
  1316. {
  1317. logicEnable = dicSetMatchPositionC1.ContainsKey(j);// && dicRfMatchProcessMode[j] == "TritonPresetMode";
  1318. }
  1319. if (cell.RecipeVariableDefine.TechnicalName == "Match.SetMatchPositionC2")
  1320. {
  1321. logicEnable = dicSetMatchPositionC2.ContainsKey(j);// && dicRfMatchProcessMode[j] == "TritonPresetMode";
  1322. }
  1323. cell.IsMasked = !logicEnable;
  1324. //update diff variable numbers
  1325. if (cell.RecipeVariableDefine.TechnicalName == "Ramp")
  1326. {
  1327. //更新当前步骤中Ramp的变量数据
  1328. if (j == 0)
  1329. {
  1330. cell.Tag = 0;
  1331. }
  1332. else
  1333. {
  1334. int rampNum = 0;
  1335. for (int s1 = 0; s1 < RecipeRows.Count; s1++)
  1336. {
  1337. if (RecipeRows[s1].CatalogName == "StepInfo")// RecipeRows[s1].RecipeItems[j].RecipeVariableDefine.CellType == CellType.ReadOnly)
  1338. continue;
  1339. string preValue = RecipeRows[s1].RecipeItems[j - 1].Value;
  1340. string curValue = RecipeRows[s1].RecipeItems[j].Value;
  1341. if (RecipeRows[s1].RecipeItems[j].RecipeVariableDefine.CellType == CellType.NumInput)
  1342. {
  1343. double pd, cd;
  1344. if (double.TryParse(preValue, out pd) && double.TryParse(curValue, out cd))
  1345. if (pd != cd) rampNum++;
  1346. }
  1347. else if (String.Compare(preValue, curValue, false) != 0)
  1348. {
  1349. rampNum++;
  1350. }
  1351. }
  1352. cell.Tag = rampNum;
  1353. }
  1354. cell.InvokePropertyChanged();
  1355. }
  1356. #region mask (hide or show cell content)
  1357. if ((MaskedTechNames != null && MaskedTechNames.Contains(cell.RecipeVariableDefine.TechnicalName)) ||
  1358. (MaskedCatalogNames != null && MaskedCatalogNames.Contains(cell.RecipeVariableDefine.CatalogName)) || !logicEnable)
  1359. cell.IsMasked = true;
  1360. else
  1361. cell.IsMasked = false;
  1362. #endregion mask (hide or show cell content)
  1363. #region check cell data range
  1364. switch (cell.RecipeVariableDefine.CellType)
  1365. {
  1366. case CellType.CheckBox:
  1367. {
  1368. if (string.Compare(cell.Value, "true", true) == 0 || string.Compare(cell.Value, "false", true) == 0)
  1369. {
  1370. cell.ErrInfo = "";
  1371. cell.Background = Brushes.Transparent;
  1372. }
  1373. else
  1374. {
  1375. string reason = string.Format("Value '{0}' not valid", cell.Value);
  1376. Errors.Add(new Tuple<int, int, string, string>(i, j, cell.RecipeVariableDefine.FriendlyName, reason));
  1377. cell.ErrInfo = reason;
  1378. cell.Background = Brushes.Pink;
  1379. }
  1380. }
  1381. break;
  1382. case CellType.EditableSelection:
  1383. {
  1384. cell.ErrInfo = "";
  1385. cell.Background = Brushes.Transparent;
  1386. }
  1387. break;
  1388. case CellType.NumInput:
  1389. {
  1390. double min = cell.RecipeVariableDefine.MinValue;
  1391. double max = cell.RecipeVariableDefine.MaxValue;
  1392. double v;
  1393. if (!double.TryParse(cell.Value, out v))
  1394. {
  1395. string reason = string.Format("Value '{0}' not valid", cell.Value);
  1396. Errors.Add(new Tuple<int, int, string, string>(i, j, cell.RecipeVariableDefine.FriendlyName, reason));
  1397. cell.ErrInfo = reason;
  1398. cell.Background = Brushes.Pink;
  1399. }
  1400. else if (v > max || v < 0 || (v < min && v > max * 0.1 / 100))
  1401. {
  1402. string reason = string.Format("Value'{0}',Out of Range {1}~{2}", cell.Value, min, max);
  1403. Errors.Add(new Tuple<int, int, string, string>(i, j, cell.RecipeVariableDefine.FriendlyName, reason));
  1404. cell.ErrInfo = reason;
  1405. cell.Background = Brushes.Pink;
  1406. }
  1407. else
  1408. {
  1409. cell.ErrInfo = "";
  1410. cell.Background = Brushes.Transparent;
  1411. }
  1412. }
  1413. break;
  1414. case CellType.ReadOnlySelection:
  1415. {
  1416. if (cell.RecipeVariableDefine.DropdownItemList != null && cell.RecipeVariableDefine.DropdownItemList.Find((o) => o.Item1 == cell.Value) != null)
  1417. {
  1418. cell.ErrInfo = "";
  1419. cell.Background = Brushes.Transparent;
  1420. }
  1421. else
  1422. {
  1423. string reason = string.Format("Value'{0}' is not valid", cell.Value);
  1424. Errors.Add(new Tuple<int, int, string, string>(i, j, cell.RecipeVariableDefine.FriendlyName, reason));
  1425. cell.ErrInfo = reason;
  1426. cell.Background = Brushes.Pink;
  1427. }
  1428. }
  1429. break;
  1430. case CellType.ReadOnly:
  1431. case CellType.TextInput:
  1432. cell.ErrInfo = "";
  1433. cell.Background = Brushes.Transparent;
  1434. break;
  1435. case CellType.TimeInput:
  1436. {
  1437. string[] arr = cell.Value.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries);
  1438. int h, mi, s;
  1439. 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)
  1440. {
  1441. cell.ErrInfo = "";
  1442. cell.Background = Brushes.Transparent;
  1443. }
  1444. else
  1445. {
  1446. string reason = string.Format("value'{0}' is not valid", cell.Value);
  1447. Errors.Add(new Tuple<int, int, string, string>(i, j, cell.RecipeVariableDefine.FriendlyName, reason));
  1448. cell.ErrInfo = reason;
  1449. cell.Background = Brushes.Pink;
  1450. }
  1451. }
  1452. break;
  1453. }
  1454. #endregion check cell data range
  1455. #region mark data trend / hide same content
  1456. if (j == 0) //step one
  1457. {
  1458. cell.Foreground = Brushes.Black;
  1459. cell.FontWeight = FontWeights.Normal;
  1460. cell.IsHidden = false;
  1461. cell.InvokePropertyChanged();
  1462. cell.IsMasked = !logicEnable;
  1463. continue;
  1464. }
  1465. var preCell = RecipeRows[i].RecipeItems[j - 1];
  1466. if (cell.RecipeVariableDefine.CellType == CellType.NumInput)
  1467. {
  1468. double preValue = 0;
  1469. double.TryParse(preCell.Value.ToString(), out preValue);
  1470. double curValue = 0;
  1471. double.TryParse(cell.Value.ToString(), out curValue);
  1472. if (curValue > preValue)
  1473. {
  1474. cell.Foreground = Brushes.Red;
  1475. cell.FontWeight = FontWeights.Bold;
  1476. }
  1477. else if (curValue < preValue)
  1478. {
  1479. cell.Foreground = Brushes.Blue;
  1480. cell.FontWeight = FontWeights.Bold;
  1481. }
  1482. else
  1483. {
  1484. cell.Foreground = Brushes.Black;
  1485. cell.FontWeight = FontWeights.Normal;
  1486. }
  1487. }
  1488. else
  1489. {
  1490. //not number type
  1491. cell.Foreground = Brushes.Black;
  1492. cell.FontWeight = FontWeights.Normal;
  1493. }
  1494. if (IsHideSameContent && cell.Value == preCell.Value)
  1495. cell.IsHidden = true;
  1496. else
  1497. cell.IsHidden = false;
  1498. //!logicEnable;
  1499. cell.IsMasked = !logicEnable;
  1500. //if (!logicEnable)
  1501. //{
  1502. // cell.Background = Brushes.DarkGray;
  1503. // cell.IsMasked = true;
  1504. //}
  1505. #endregion mark data trend / hide same content
  1506. cell.InvokePropertyChanged();
  1507. }
  1508. }
  1509. #region check loop
  1510. int loopRowId = -1;
  1511. for (int i = 0; i < RecipeRows.Count; i++)
  1512. {
  1513. if (RecipeRows[i].TechnicalName == "Loop")
  1514. {
  1515. loopRowId = i;
  1516. break;
  1517. }
  1518. }
  1519. for (int j = 0; j < RecipeRows[loopRowId].RecipeItems.Count; j++)
  1520. {
  1521. var cell = RecipeRows[loopRowId].RecipeItems[j];
  1522. bool isLoopStart = Regex.IsMatch(cell.Value, @"^Loop\x20\d+$");
  1523. bool isLoopEnd = Regex.IsMatch(cell.Value, @"^Loop End$");
  1524. bool isNullOrEmpty = string.IsNullOrWhiteSpace(cell.Value);
  1525. if (!isLoopEnd && !isLoopStart && !isNullOrEmpty)
  1526. {
  1527. string reason = string.Format("Value '{0}' not valid", cell.Value);
  1528. cell.ErrInfo = reason;
  1529. cell.Background = Brushes.Pink;
  1530. Errors.Add(new Tuple<int, int, string, string>(loopRowId, j, cell.RecipeVariableDefine.FriendlyName, reason));
  1531. }
  1532. if (isLoopEnd)
  1533. {
  1534. string reason = "Loop Start 缺失";
  1535. cell.ErrInfo = reason;
  1536. cell.Background = Brushes.Pink;
  1537. Errors.Add(new Tuple<int, int, string, string>(loopRowId, j, cell.RecipeVariableDefine.FriendlyName, reason));
  1538. }
  1539. else if (isLoopStart)
  1540. {
  1541. for (int k = j + 1; k < RecipeRows[loopRowId].RecipeItems.Count; k++)
  1542. {
  1543. cell = RecipeRows[loopRowId].RecipeItems[k];
  1544. bool isCurStepLoopStart = Regex.IsMatch(cell.Value, @"^Loop\x20\d+$");
  1545. bool isCurStepLoopEnd = Regex.IsMatch(cell.Value, @"^Loop End$");
  1546. isNullOrEmpty = string.IsNullOrWhiteSpace(cell.Value);
  1547. if (!isCurStepLoopEnd && !isCurStepLoopStart && !isNullOrEmpty)
  1548. {
  1549. string reason = string.Format("Value '{0}' not valid", cell.Value);
  1550. cell.ErrInfo = reason;
  1551. cell.Background = Brushes.Pink;
  1552. Errors.Add(new Tuple<int, int, string, string>(loopRowId, k, cell.RecipeVariableDefine.FriendlyName, reason));
  1553. }
  1554. else if (isCurStepLoopStart)
  1555. {
  1556. string reason = "前面循环没有结束,不能设置新的Loop Start标志";
  1557. cell.ErrInfo = reason;
  1558. cell.Background = Brushes.Pink;
  1559. Errors.Add(new Tuple<int, int, string, string>(loopRowId, k, cell.RecipeVariableDefine.FriendlyName, reason));
  1560. }
  1561. else if (isCurStepLoopEnd)
  1562. {
  1563. //mark loop steps with blue background
  1564. for (int m1 = j; m1 <= k; m1++)
  1565. {
  1566. var curCell = RecipeRows[loopRowId].RecipeItems[m1];
  1567. if (curCell.Background == Brushes.Transparent)
  1568. curCell.Background = Brushes.LightGreen;
  1569. curCell.InvokePropertyChanged();
  1570. }
  1571. j = k;
  1572. break;
  1573. }
  1574. if (k == RecipeRows[loopRowId].RecipeItems.Count - 1)
  1575. {
  1576. j = k;
  1577. string reason = "Loop End 缺失";
  1578. cell.ErrInfo = reason;
  1579. cell.Background = Brushes.Pink;
  1580. Errors.Add(new Tuple<int, int, string, string>(loopRowId, k, cell.RecipeVariableDefine.FriendlyName, reason));
  1581. }
  1582. }
  1583. }
  1584. }
  1585. #endregion check loop
  1586. #region recipe parameter validation
  1587. //using (var lua = new LuaInterface.Lua())
  1588. //{
  1589. // //is special recipe?
  1590. // //bool IsSpecialRecipe = true;
  1591. // //{
  1592. // // int heaterModeRowIndex = RowVarNameDic["Heater.Mode"];
  1593. // // int aZoneSetpointIndex = RowVarNameDic["AZone.Setpoint"];
  1594. // // int bZoneSetpointIndex = RowVarNameDic["BZone.Setpoint"];
  1595. // // int cZoneSetpointIndex = RowVarNameDic["CZone.Setpoint"];
  1596. // // int dZoneSetpointIndex = RowVarNameDic.ContainsKey("DZone.Setpoint") ? RowVarNameDic["DZone.Setpoint"] : aZoneSetpointIndex;
  1597. // // for (int stepIndex = 0; stepIndex < RecipeRows[0].RecipeItems.Count; stepIndex++)
  1598. // // {
  1599. // // if (RecipeRows[heaterModeRowIndex].RecipeItems[stepIndex].Value != "CurrentControl" ||
  1600. // // RecipeRows[aZoneSetpointIndex].RecipeItems[stepIndex].Value != "0" ||
  1601. // // RecipeRows[bZoneSetpointIndex].RecipeItems[stepIndex].Value != "0" ||
  1602. // // RecipeRows[cZoneSetpointIndex].RecipeItems[stepIndex].Value != "0" ||
  1603. // // RecipeRows[dZoneSetpointIndex].RecipeItems[stepIndex].Value != "0")
  1604. // // {
  1605. // // IsSpecialRecipe = false;
  1606. // // break;
  1607. // // }
  1608. // // }
  1609. // //}
  1610. // ////set get ramp rate function
  1611. // //lua.RegisterFunction("CheckRampRate", this, GetType().GetMethod("CheckRampRate"));
  1612. // //lua.DoString(string.Format("IsProductionRecipe={0};",(!IsSpecialRecipe).ToString().ToLower()));
  1613. // for (int stepIndex = 0; stepIndex < RecipeRows[0].RecipeItems.Count; stepIndex++)
  1614. // {
  1615. // //set stepNo
  1616. // lua.DoString(string.Format("StepNo={0};", stepIndex));
  1617. // //reading var from current recipe step
  1618. // foreach (var checkVar in _checkVariables)
  1619. // {
  1620. // if (!RowVarNameDic.ContainsKey(checkVar))
  1621. // {
  1622. // System.Diagnostics.Debug.WriteLine("检查不到变量定义," + checkVar);
  1623. // continue;
  1624. // }
  1625. // try
  1626. // {
  1627. // int varId = RowVarNameDic[checkVar];
  1628. // if (RecipeRows[varId].RecipeItems[stepIndex].RecipeVariableDefine.CellType == CellType.NumInput)
  1629. // lua.DoString(string.Format("{0}={1};", RecipeRows[varId].RecipeItems[stepIndex].RecipeVariableDefine.TechnicalName.Replace(".", "_"), RecipeRows[varId].RecipeItems[stepIndex].Value));
  1630. // else
  1631. // lua.DoString(string.Format("{0}=\"{1}\";", RecipeRows[varId].RecipeItems[stepIndex].RecipeVariableDefine.TechnicalName.Replace(".", "_"), RecipeRows[varId].RecipeItems[stepIndex].Value));
  1632. // }
  1633. // catch (Exception ex)
  1634. // {
  1635. // System.Diagnostics.Debug.WriteLine("校验异常," + ex);
  1636. // }
  1637. // }
  1638. // //reading from recipe format file
  1639. // foreach (string key in _preDefinedRecipeVars.Keys)
  1640. // {
  1641. // string varValueString = _preDefinedRecipeVars[key];
  1642. // double varValue;
  1643. // if (double.TryParse(varValueString, out varValue))
  1644. // lua.DoString(string.Format("{0}={1};", key, varValue));
  1645. // else
  1646. // lua.DoString(string.Format("{0}=\"{1}\";", key, varValueString));
  1647. // }
  1648. // //do valation
  1649. // foreach (var rule in _validationRules)
  1650. // {
  1651. // lua.DoString(string.Format("if {0} then hasErr=1 else hasErr=0 end", rule.Item2));
  1652. // bool hasError = ((int)lua.GetNumber("hasErr")) == 1;
  1653. // if (hasError)
  1654. // {
  1655. // lua.DoString(string.Format("message=string.format({0});", rule.Item3));
  1656. // string reason = lua.GetString("message");
  1657. // var rowId = RowVarNameDic[rule.Item1];
  1658. // var cell = RecipeRows[rowId].RecipeItems[stepIndex];
  1659. // cell.ErrInfo = reason;
  1660. // cell.Background = Brushes.Pink;
  1661. // Errors.Add(new Tuple<int, int, string, string>(rowId, stepIndex, cell.RecipeVariableDefine.FriendlyName, reason));
  1662. // cell.InvokePropertyChanged();
  1663. // }
  1664. // }
  1665. // }
  1666. //}
  1667. #endregion recipe parameter validation
  1668. #region update material cell data
  1669. int materialRowId = -1;
  1670. for (int colId = 0; colId < RecipeRows[0].RecipeItems.Count; colId++)
  1671. {
  1672. string materialName = "";
  1673. for (int rowId = 0; rowId < RecipeRows.Count; rowId++)
  1674. {
  1675. string curMo = "";
  1676. if (materialRowId == -1 && RecipeRows[rowId].RecipeItems[colId].RecipeVariableDefine.TechnicalName == "Material")
  1677. {
  1678. materialRowId = rowId;
  1679. }
  1680. var cell = RecipeRows[rowId].RecipeItems[colId];
  1681. if (cell.RecipeVariableDefine.CellType == CellType.ReadOnlySelection && String.Compare(cell.Value, "flow", true) == 0)
  1682. {
  1683. string moName = cell.RecipeVariableDefine.TechnicalName.Split('.')[0].ToLower();
  1684. string displayName = cell.RecipeVariableDefine.FriendlyName.Replace("_", ".").Split('.')[0].ToLower();
  1685. if (moName.Contains("cp2mg_1") || displayName.Contains("cp2mg_1")) curMo = "Mg1";
  1686. else if (moName.Contains("cp2mg_2") || displayName.Contains("cp2mg_2")) curMo = "Mg2";
  1687. else if (moName.Contains("cp2mg_3") || displayName.Contains("cp2mg_3")) curMo = "Mg3";
  1688. else if (moName.Contains("cp2mg_4") || displayName.Contains("cp2mg_4")) curMo = "Mg4";
  1689. else if (moName.Contains("cp2mg") || displayName.Contains("cp2mg")) curMo = "Mg";
  1690. else if (moName.Contains("tmin") || displayName.Contains("tmin")) curMo = "In";
  1691. else if (moName.Contains("tmin_1") || displayName.Contains("tmin_1")) curMo = "In1";
  1692. else if (moName.Contains("tmin_2") || displayName.Contains("tmin_2")) curMo = "In2";
  1693. else if (moName.Contains("tmin_3") || displayName.Contains("tmin_3")) curMo = "In3";
  1694. else if (moName.Contains("tmin_4") || displayName.Contains("tmin_4")) curMo = "In4";
  1695. else if (moName.Contains("tmga") || displayName.Contains("tmga")) curMo = "TMG";
  1696. else if (moName.Contains("tmga_1") || displayName.Contains("tmga_1")) curMo = "TMG1";
  1697. else if (moName.Contains("tmga_2") || displayName.Contains("tmga_2")) curMo = "TMG2";
  1698. else if (moName.Contains("tmga_3") || displayName.Contains("tmga_3")) curMo = "TMG3";
  1699. else if (moName.Contains("tmga_4") || displayName.Contains("tmga_4")) curMo = "TMG4";
  1700. else if (moName.Contains("tega") || displayName.Contains("tega")) curMo = "TEG";
  1701. else if (moName.Contains("tega_1") || displayName.Contains("tega_1")) curMo = "TEG1";
  1702. else if (moName.Contains("tega_2") || displayName.Contains("tega_2")) curMo = "TEG2";
  1703. else if (moName.Contains("tega_3") || displayName.Contains("tega_3")) curMo = "TEG3";
  1704. else if (moName.Contains("tega_4") || displayName.Contains("tega_4")) curMo = "TEG4";
  1705. else if (moName.Contains("tmal") || displayName.Contains("tmal")) curMo = "TAl";
  1706. else if (moName.Contains("tmal_1") || displayName.Contains("tmal_1")) curMo = "TAl1";
  1707. else if (moName.Contains("tmal_2") || displayName.Contains("tmal_2")) curMo = "TAl2";
  1708. else if (moName.Contains("tmal_3") || displayName.Contains("tmal_3")) curMo = "TAl3";
  1709. else if (moName.Contains("tmal_4") || displayName.Contains("tmal_4")) curMo = "TAl4";
  1710. else if (moName.Contains("nh3source") || displayName.Contains("nh3source")) curMo = "NH3";
  1711. else if (moName.Contains("si")) curMo = "Si";
  1712. if (!string.IsNullOrEmpty(curMo))
  1713. {
  1714. if (string.IsNullOrEmpty(materialName))
  1715. materialName = curMo;
  1716. else
  1717. materialName += "|" + curMo;
  1718. }
  1719. }
  1720. }
  1721. if (materialRowId >= 0)
  1722. {
  1723. RecipeRows[materialRowId].RecipeItems[colId].Value = materialName;
  1724. RecipeRows[materialRowId].RecipeItems[colId].InvokePropertyChanged();
  1725. }
  1726. }
  1727. #endregion update material cell data
  1728. #region update column header
  1729. if (DataGridControl.Columns.Count - 1 == RecipeRows[0].RecipeItems.Count)
  1730. {
  1731. var redColHeader = (DataTemplate)DataGridControl.FindResource("columnRedTitleTemplate");
  1732. var blackColHeader = (DataTemplate)DataGridControl.FindResource("columnBlackTitleTemplate");
  1733. for (int j = 0; j < RecipeRows[0].RecipeItems.Count; j++)
  1734. {
  1735. DataGridControl.Columns[j + 1].Title = string.Format("{0}|{2}\r\n{1}", j + 1, RecipeRows[0].RecipeItems[j].Value, RecipeRows[2].RecipeItems[j].Value);
  1736. if (Errors.Find((o) => o.Item2 == j) != null)
  1737. DataGridControl.Columns[j + 1].TitleTemplate = redColHeader;
  1738. else
  1739. DataGridControl.Columns[j + 1].TitleTemplate = blackColHeader;
  1740. }
  1741. }
  1742. #endregion update column header
  1743. #region if running state, highlight current running step, move horizontal bar to current running step
  1744. if (CurrentRunningStepNo > 0 && DataGridControl.Columns.Count > 2)
  1745. {
  1746. for (int rowId = 0; rowId < RecipeRows.Count; rowId++)
  1747. {
  1748. for (int colId = 0; colId < RecipeRows[0].RecipeItems.Count; colId++)
  1749. {
  1750. var cell = RecipeRows[rowId].RecipeItems[colId];
  1751. if (colId + 1 == CurrentRunningStepNo)
  1752. {
  1753. cell.IsRunning = true;
  1754. }
  1755. else
  1756. {
  1757. cell.IsRunning = false;
  1758. }
  1759. cell.InvokePropertyChanged("IsRunning");
  1760. }
  1761. }
  1762. if (moving2RunningStepPosition)
  1763. {
  1764. Task.Factory.StartNew(() =>
  1765. {
  1766. System.Threading.Thread.Sleep(200);
  1767. DataGridControl.Dispatcher.Invoke(new Action(() =>
  1768. {
  1769. double singleWidth = DataGridControl.Columns[1].Width;
  1770. double horizontalOffset = (CurrentRunningStepNo - 2) * singleWidth;
  1771. if (DataGridControl.ScrollViewer != null)
  1772. {
  1773. if (horizontalOffset > DataGridControl.ScrollViewer.ScrollableWidth)
  1774. horizontalOffset = DataGridControl.ScrollViewer.ScrollableWidth;
  1775. if (horizontalOffset < 0)
  1776. horizontalOffset = 0;
  1777. DataGridControl.ScrollViewer.ScrollToHorizontalOffset(horizontalOffset);
  1778. }
  1779. }));
  1780. });
  1781. }
  1782. }
  1783. #endregion if running state, highlight current running step, move horizontal bar to current running step
  1784. //calc recipe time
  1785. CalcRecipeTime();
  1786. //invoke property
  1787. InvokePropertyChanged("Errors");
  1788. }
  1789. catch (Exception ex)
  1790. {
  1791. MessageBox.Show("工艺程序校验出错!\r\n\r\n" + ex.Message, "出错", MessageBoxButton.OK, MessageBoxImage.Error);
  1792. System.Diagnostics.Debug.WriteLine(ex.Message);
  1793. }
  1794. }
  1795. /// <summary>
  1796. /// reload datagrid content
  1797. /// </summary>
  1798. private void RefreshDataGrid()
  1799. {
  1800. try
  1801. {
  1802. //generate columns in Grid
  1803. DataGridControl.CurrentColumn = null;
  1804. if (DataGridControl.Columns.Count > 0)
  1805. DataGridControl.Columns.Clear();
  1806. var template = (DataTemplate)DataGridControl.FindResource("CustomTemplate");
  1807. var rowTemplate = (DataTemplate)DataGridControl.FindResource("RowHeadTemplate");
  1808. DataGridControl.Columns.Add(new Xceed.Wpf.DataGrid.Column()
  1809. {
  1810. Width = 140,
  1811. Title = " ",
  1812. FieldName = ".",
  1813. CellContentTemplate = rowTemplate
  1814. });
  1815. var cellEditor = DataGridControl.DefaultCellEditors[typeof(SmartCellData)];// DefaultCellEditorSelector.SelectCellEditor(typeof(SmartCellData));
  1816. for (int index = 0; index < RecipeRows[0].RecipeItems.Count; index++)
  1817. {
  1818. //var col = new Xceed.Wpf.DataGrid.Column();
  1819. DataGridControl.Columns.Add(new Xceed.Wpf.DataGrid.Column()
  1820. {
  1821. Title = string.Format("【{0}】\r\n{1}", index + 1, RecipeRows[0].RecipeItems[index].Value),
  1822. FieldName = string.Format("RecipeItems[{0}]", index),
  1823. CellContentTemplate = template,
  1824. AllowSort = false,
  1825. Width = 120,
  1826. MaxWidth = 120,
  1827. CellEditor = cellEditor
  1828. });
  1829. }
  1830. InvokePropertyChanged("RecipeRows");
  1831. InvokePropertyChanged("RecipeHead");
  1832. }
  1833. catch (Exception ex)
  1834. {
  1835. System.Diagnostics.Debug.WriteLine(ex.Message);
  1836. }
  1837. }
  1838. /// <summary>
  1839. /// calc recipe total time
  1840. /// </summary>
  1841. private void CalcRecipeTime()
  1842. {
  1843. int timeStepRowId = -1;
  1844. int loopStepRowId = -1;
  1845. for (int i = 0; i < RecipeRows.Count; i++)
  1846. {
  1847. if (RecipeRows[i].TechnicalName == "Time")
  1848. timeStepRowId = i;
  1849. if (RecipeRows[i].TechnicalName == "Loop")
  1850. loopStepRowId = i;
  1851. if (loopStepRowId != -1 && timeStepRowId != -1)
  1852. break;
  1853. }
  1854. TimeSpan tspan = new TimeSpan();
  1855. for (int stepNo = 0; stepNo < RecipeRows[timeStepRowId].RecipeItems.Count; stepNo++)
  1856. {
  1857. string loopStr = RecipeRows[loopStepRowId].RecipeItems[stepNo].Value;
  1858. bool isLoopStart = Regex.IsMatch(loopStr, @"^Loop\x20\d+$");
  1859. if (isLoopStart)
  1860. {
  1861. int loopNum = int.Parse(loopStr.ToLower().Replace("loop", "").Replace(" ", ""));
  1862. TimeSpan ts = new TimeSpan();
  1863. for (int innerStepNo = stepNo; innerStepNo < RecipeRows[timeStepRowId].RecipeItems.Count; innerStepNo++)
  1864. {
  1865. loopStr = RecipeRows[loopStepRowId].RecipeItems[innerStepNo].Value;
  1866. stepNo = innerStepNo;
  1867. string timeDuration = RecipeRows[timeStepRowId].RecipeItems[innerStepNo].Value;
  1868. string[] timeArr = timeDuration.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries);
  1869. if (timeArr.Length == 3)
  1870. {
  1871. int h, mi, s;
  1872. if (int.TryParse(timeArr[0], out h) && int.TryParse(timeArr[1], out mi) && int.TryParse(timeArr[2], out s))
  1873. {
  1874. var tt = new TimeSpan(h, mi, s);
  1875. ts += tt;
  1876. }
  1877. }
  1878. bool isLoopEnd = Regex.IsMatch(loopStr, @"^Loop End$");
  1879. if (isLoopEnd)
  1880. {
  1881. tspan += new TimeSpan(ts.Ticks * loopNum);
  1882. break;
  1883. }
  1884. }
  1885. }
  1886. else
  1887. {
  1888. string timeDuration = RecipeRows[timeStepRowId].RecipeItems[stepNo].Value;
  1889. string[] timeArr = timeDuration.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries);
  1890. if (timeArr.Length == 3)
  1891. {
  1892. int h, mi, s;
  1893. if (int.TryParse(timeArr[0], out h) && int.TryParse(timeArr[1], out mi) && int.TryParse(timeArr[2], out s))
  1894. {
  1895. var ts = new TimeSpan(h, mi, s);
  1896. tspan += ts;
  1897. }
  1898. }
  1899. }
  1900. }
  1901. RecipeInfo = string.Format("共{0}步,总时间{1}:{2}:{3}", RecipeRows[0].RecipeItems.Count, (int)tspan.TotalHours, tspan.Minutes.ToString("00"), tspan.Seconds.ToString("00"));
  1902. InvokePropertyChanged("RecipeInfo");
  1903. }
  1904. #region INotifyPropertyChanged
  1905. public event PropertyChangedEventHandler PropertyChanged;
  1906. public void InvokePropertyChanged(string propertyName)
  1907. {
  1908. if (PropertyChanged != null)
  1909. {
  1910. PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
  1911. }
  1912. }
  1913. #endregion INotifyPropertyChanged
  1914. }
  1915. public class RecipePredefine123
  1916. {
  1917. /// <summary>
  1918. /// 最大升温速度 C/sec
  1919. /// </summary>
  1920. public double MaxTempRampUpRate { get; set; }
  1921. /// <summary>
  1922. /// 最大降温速度 C/sec
  1923. /// </summary>
  1924. public double MaxTempRampDownRate { get; set; }
  1925. /// <summary>
  1926. /// 加热区允许的最大温差设定值 C
  1927. /// </summary>
  1928. public double MaxTempDT { get; set; }
  1929. /// <summary>
  1930. /// Heat Purge最小流量设定 sccm
  1931. /// </summary>
  1932. public double MinHeatPurge { get; set; }
  1933. /// <summary>
  1934. /// Spindle最低转速 rpm
  1935. /// </summary>
  1936. public double MinSpindleSpeed { get; set; }
  1937. /// <summary>
  1938. /// 腔体压力允许最低设定值 mbar
  1939. /// </summary>
  1940. public double MinPressureSetpoint { get; set; }
  1941. /// <summary>
  1942. /// 最大压力伺服速度 mbar/sec
  1943. /// </summary>
  1944. public double MaxPressRampRate { get; set; }
  1945. /// <summary>
  1946. /// 最大转盘旋转加速度 rpm/sec
  1947. /// </summary>
  1948. public double MaxSpindleRampRate { get; set; }
  1949. /// <summary>
  1950. /// 最大温度设定值
  1951. /// </summary>
  1952. public double MaxTempSetpoint { get; set; }
  1953. /// <summary>
  1954. /// 最大电流设定值
  1955. /// </summary>
  1956. public double AZoneMaxCurrentSetpoint { get; set; }
  1957. public double BZoneMaxCurrentSetpoint { get; set; }
  1958. public double CZoneMaxCurrentSetpoint { get; set; }
  1959. public double DZoneMaxCurrentSetpoint { get; set; }
  1960. }
  1961. public class RecipeRow
  1962. {
  1963. private ObservableCollection<SmartCellData> _recipeItems = new ObservableCollection<SmartCellData>();
  1964. public RecipeRow(params SmartCellData[] vars)
  1965. {
  1966. foreach (var var in vars)
  1967. _recipeItems.Add(var);
  1968. }
  1969. public string CatalogName { get; set; }
  1970. public string FriendlyName { get; set; }
  1971. public string TechnicalName { get; set; }
  1972. public ObservableCollection<SmartCellData> RecipeItems
  1973. {
  1974. get { return _recipeItems; }
  1975. set { _recipeItems = value; }
  1976. }
  1977. }
  1978. /// <summary>
  1979. /// Recipe head
  1980. /// </summary>
  1981. public class RecipeHead
  1982. {
  1983. public string RecipeVariation { get; set; }
  1984. public string CreationTime { get; set; }
  1985. public string LastRevisionTime { get; set; }
  1986. public string CreatedBy { get; set; }
  1987. public string LastModifiedBy { get; set; }
  1988. public string PressureMode { get; set; }
  1989. public string Description { get; set; }
  1990. public string BasePressure
  1991. {
  1992. get; set;
  1993. }
  1994. public string PumpDownLimit
  1995. {
  1996. get; set;
  1997. }
  1998. public string PurgeActive
  1999. {
  2000. get; set;
  2001. }
  2002. public string Barcode
  2003. {
  2004. get; set;
  2005. }
  2006. public string SubstrateTemp
  2007. {
  2008. get; set;
  2009. }
  2010. public string PumpingPinState
  2011. {
  2012. get; set;
  2013. }
  2014. public string PinStateAfterVent
  2015. {
  2016. get; set;
  2017. }
  2018. public string PinDownPressure
  2019. {
  2020. get; set;
  2021. }
  2022. }
  2023. }