RecipeEditorControlViewModel.cs 107 KB

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