using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Input; using System.Windows.Media; using System.Xml; using Aitex.UI.RecipeEditor.Core; using Aitex.UI.RecipeEditor.View; using ExcelLibrary.SpreadSheet; using Microsoft.Win32; using Xceed.Wpf.DataGrid; namespace Aitex.UI.RecipeEditor { public class RecipeEditorControlViewModel : INotifyPropertyChanged { private ObservableCollection m_RecipeModelObservableCollection = new ObservableCollection(); public ObservableCollection RecipeModelObservableCollection { get { return m_RecipeModelObservableCollection; } set { m_RecipeModelObservableCollection = value; InvokePropertyChanged("RecipeModelObservableCollection"); } } private Visibility m_DataGridVisibility=Visibility.Collapsed; public Visibility DataGridVisibility { get { return m_DataGridVisibility; } set { m_DataGridVisibility = value; InvokePropertyChanged("DataGridVisibility"); } } public ICommand AddStepCommand { get; set; } public ICommand DeleteStepCommand { get; set; } public List, Guid>> UndoList { get; set; } public List, Guid>> RedoList { get; set; } public bool IsUndoEnabled { get { return UndoList != null && UndoList.Count > 0; } } public bool IsRedoEnabled { get { return RedoList != null && RedoList.Count > 0; } } public ObservableCollection RecipeRows { get; set; } private ObservableCollection _previousRecipeRows { get; set; } private string _valueBeforeEditing { get; set; } private string _currentRecipeVariationName = string.Empty; private SmartCellData _currentEditingCellData { get; set; } public List> Errors { get; set; } public List> CreateRecipeList { get; set; } public List> OpenRecipeList { get; set; } public DataGrid DataGridControl { get; set; } public int CurrentRunningStepNo { get; set; } public Visibility SingleAppElementVisibility { get; set; } public Visibility RecipeInfoTextVisibility { get; set; } public ICommand ShowDetailedErrInfoCommand { get; set; } public ICommand EditRecipeInfoCommand { get; set; } //public ICommand CellContentChangedCommand { get; set; } public ICommand RightClickCommand { get; set; } public ICommand OpenLocalRecipeCommand { get; set; } public ICommand ExpandGroupCommand { get; set; } public ICommand CollapseGroupCommand { get; set; } public ICommand SaveRecipeCommand { get; set; } public ICommand RecipeHelpDocCommand { get; set; } public ICommand RecipeExport2ExcelCommand { get; set; } public ICommand ToggleHideSameCommand { get; set; } public ICommand UndoCommand { get; set; } public ICommand RedoCommand { get; set; } public ICommand SmartCellEditorLoadedCommand { get; set; } public ICommand SmartCellEditorUnloadedCommand { get; set; } public RecipeHead RecipeHead { get; set; } public bool IsBusy { get; set; } public bool IsHideSameContent { get; set; } public string RecipeInfo { get; set; } public HashSet MaskedTechNames { get; set; } public HashSet MaskedCatalogNames { get; set; } public event EventHandler OnSaveRecipeFile; public event EventHandler OnLocalRecipeOpened; public event EventHandler OnLoadRecipeContent; public bool IsRecipeModified { get; set; } public string UserName { set; get; } //private List> SourceDilteInjectRestrictions { get; set; } private Dictionary _preDefinedRecipeVars { get; set; } private List> _validationRules { get; set; } private List _checkVariables { get; set; } private Dictionary RowVarNameDic { get; set; } private Dictionary> _copiedColumnDatas = new Dictionary>(); private Dictionary>> _recipeReadingFormat; private Dictionary/*each item's control name*/> _recipeSavingFormat; private string _currentRecipeFormatContent; public bool IsBarcodeEnabled { get; set; } public Visibility IsBarcodeVisibility { get { return IsBarcodeEnabled ? Visibility.Visible : Visibility.Hidden; } } private string _defaultEndPointValue { get; set; } /// /// class construction /// public RecipeEditorControlViewModel() { UndoList = new List, Guid>>(); RedoList = new List, Guid>>(); //if(SingleAppElementVisibility CreateRecipeList = new List>(); OpenRecipeList = new List>(); foreach (var item in GetDefinedRecipeVariations()) { CreateRecipeList.Add(new Tuple("配置:" + item, item)); OpenRecipeList.Add(new Tuple("转换为配置:" + item, item)); } RecipeInfoTextVisibility = Visibility.Collapsed; SingleAppElementVisibility = Visibility.Collapsed; RightClickCommand = new DelegatedCommand((o) => true, (o) => RightClickAction()); SaveRecipeCommand = new DelegatedCommand((o) => true, (o) => SaveRecipeFile()); OpenLocalRecipeCommand = new DelegatedCommand((o) => true, (o) => OpenLocalRecipe()); ShowDetailedErrInfoCommand = new DelegatedCommand((o) => true, (o) => ShowDetailedErrInformation()); EditRecipeInfoCommand = new DelegatedCommand((o) => true, (o) => EditRecipeInformation()); RecipeHelpDocCommand = new DelegatedCommand((o) => true, (o) => ShowHelpDocView()); ToggleHideSameCommand = new DelegatedCommand((o) => true, (o) => ToggleHideSameContent()); AddStepCommand = new DelegatedCommand((o) => true, (o) => OnAddStep()); DeleteStepCommand = new DelegatedCommand((o) => true, (o) => OnDeleteStep()); } private void OnAddStep() { RecipeModelObservableCollection.Add(new RecipeModel() { Name = "Zack",StepEndMode="Time" ,ValveControlMode="VAT"}); } private void OnDeleteStep() { RecipeModelObservableCollection.RemoveAt(RecipeModelObservableCollection.Count-1); } /// /// hide or show same content before and after one step /// private void ToggleHideSameContent() { IsHideSameContent = !IsHideSameContent; RefreshCellsDisplay(false); } /// /// get recipe variations /// /// public List GetDefinedRecipeVariations() { var list1 = new List(); var dir = new System.IO.FileInfo(Process.GetCurrentProcess().MainModule.FileName).Directory; string cfgPath = dir + "\\Config\\"; var di = new System.IO.DirectoryInfo(cfgPath); if (di.Exists) { foreach (var item in di.GetFiles("*.xml")) { list1.Add(item.Name.Substring(0, item.Name.Length - item.Extension.Length)); } } return list1; } /// /// Show recipe information /// private void ShowHelpDocView() { var view = RecipeHelpView.Instance; view.Owner = Application.Current.MainWindow; view.DataContext = this; if (view.Visibility == Visibility.Visible) view.Hide(); else view.Show(); } /// /// Edit recipe information /// private void EditRecipeInformation() { RecipeInfoEditor editor = new RecipeInfoEditor() { RecipeHead = this.RecipeHead, Owner = Application.Current.MainWindow }; editor.ShowDialog(); InvokePropertyChanged("RecipeHead"); } public void EnableBarcode(bool enable) { IsBarcodeEnabled = enable; InvokePropertyChanged("IsBarcodeVisibility"); } public void SetCurrentUser(string user) { UserName = user; InvokePropertyChanged("UserName"); } public void SetEndPointDefaultValue(string defaultValue) { _defaultEndPointValue = defaultValue; } /// /// Show recipe information /// private void ShowDetailedErrInformation() { var view = ErrorInformationDetailsView.Instance; view.Owner = Application.Current.MainWindow; view.DataContext = this; if (view.Visibility == Visibility.Visible) view.Hide(); else view.ShowDialog(); } /// /// Update selected cells data /// /// overrided cells number private int OverrideSelectedCellsData() { int overridedCellsNum = 0; //if (_currentEditingCellData != null) //{ // var finalCellData = _currentEditingCellData; // bool containsEditingCell = false; // foreach (var item in DataGridControl.SelectedCellRanges) // { // int startColIndex = Math.Min(item.ColumnRange.StartIndex, item.ColumnRange.EndIndex); // int endColIndex = Math.Max(item.ColumnRange.StartIndex, item.ColumnRange.EndIndex); // int startRowIndex = Math.Min(item.ItemRange.StartIndex, item.ItemRange.EndIndex); // int endRowIndex = Math.Max(item.ItemRange.StartIndex, item.ItemRange.EndIndex); // if (startColIndex > 0 && startColIndex <= RecipeRows[0].RecipeItems.Count && // endColIndex > 0 && endColIndex <= RecipeRows[0].RecipeItems.Count && // startRowIndex >= 0 && startRowIndex < RecipeRows.Count && // endRowIndex >= 0 && endRowIndex < RecipeRows.Count) // { // for (int m = startRowIndex; m <= endRowIndex; m++) // { // for (int n = startColIndex; n <= endColIndex; n++) // { // int rowIndex = m; // int colIndex = n - 1; // if (RecipeRows[rowIndex].RecipeItems[colIndex] == _currentEditingCellData) // { // containsEditingCell = true; // break; // } // } // } // } // } // if (containsEditingCell) // { // foreach (var item in DataGridControl.SelectedCellRanges) // { // int startColIndex = Math.Min(item.ColumnRange.StartIndex, item.ColumnRange.EndIndex); // int endColIndex = Math.Max(item.ColumnRange.StartIndex, item.ColumnRange.EndIndex); // int startRowIndex = Math.Min(item.ItemRange.StartIndex, item.ItemRange.EndIndex); // int endRowIndex = Math.Max(item.ItemRange.StartIndex, item.ItemRange.EndIndex); // if (startColIndex > 0 && startColIndex <= RecipeRows[0].RecipeItems.Count && // endColIndex > 0 && endColIndex <= RecipeRows[0].RecipeItems.Count && // startRowIndex >= 0 && startRowIndex < RecipeRows.Count && // endRowIndex >= 0 && endRowIndex < RecipeRows.Count) // { // for (int m = startRowIndex; m <= endRowIndex; m++) // { // for (int n = startColIndex; n <= endColIndex; n++) // { // int rowIndex = m; // int colIndex = n - 1; // if (RecipeRows[rowIndex].RecipeItems[colIndex].RecipeVariableDefine.CellType == finalCellData.RecipeVariableDefine.CellType) // { // overridedCellsNum++; // RecipeRows[rowIndex].RecipeItems[colIndex].Value = finalCellData.Value; // RecipeRows[rowIndex].RecipeItems[colIndex].InvokePropertyChanged(); // } // } // } // } // } // } //} return overridedCellsNum; } /// /// Open local recipe operation /// /// public void OpenLocalRecipe(string recipeVariationName = "") { var dlg = new OpenFileDialog(); dlg.DefaultExt = ".rcp"; dlg.Filter = "Recipe File (.rcp)|*.rcp|All (*.*)|*.*"; if (dlg.ShowDialog() == true) { try { XmlDocument rcpDoc = new XmlDocument(); rcpDoc.Load(dlg.FileName); string recipeVariation = recipeVariationName; if (string.IsNullOrEmpty(recipeVariation)) { var root = rcpDoc.SelectSingleNode("/TableRecipeData") as XmlElement; recipeVariation = root.Attributes["RecipeVersion"].Value; } var startupPath = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName; string dir = System.IO.Path.GetDirectoryName(startupPath); List map = CustomXmlSerializer.Deserialize>(new System.IO.FileInfo(System.IO.Path.Combine(dir, "map.xml"))); Func predicate = item => item.Name.Equals(recipeVariation); System.IO.FileInfo fi = new System.IO.FileInfo(string.Format("{0}\\config\\{1}.xml", dir, map.Any(predicate) ? map.Single(predicate).No : recipeVariation)); if (fi.Exists) { XmlDocument doc = new XmlDocument(); doc.Load(fi.FullName); string formatXml = doc.SelectSingleNode("/Aitex/TableRecipeFormat").OuterXml; string recipeXml = rcpDoc.SelectSingleNode("/TableRecipeData").OuterXml; LoadRecipe(formatXml, recipeXml); if (OnLocalRecipeOpened != null) OnLocalRecipeOpened.Invoke(new Tuple(recipeVariation, dlg.FileName), null); } else { MessageBox.Show(string.Format("工艺程序版本{0}的描述文件不存在,无法正确识别该版本的工艺程序文件。", recipeVariation), "工艺程序打开失败", MessageBoxButton.OK, MessageBoxImage.Error); } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.Message); 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", MessageBoxButton.OK, MessageBoxImage.Error); } } } /// /// Save recipe file /// private void SaveRecipeFile() { try { if (Errors != null && Errors.Count > 0) { var ret = MessageBox.Show(string.Format("Recipe have {0} error,continue save?", Errors.Count), "Save", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No); if (ret != MessageBoxResult.Yes) return; } if (OnSaveRecipeFile != null) { IsRecipeModified = false; OnSaveRecipeFile.Invoke(GetRecipeContentString(), null); } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.Message); MessageBox.Show("save recipe failed!\r\n\r\n" + ex.Message, "Save", MessageBoxButton.OK, MessageBoxImage.Warning); } } /// /// get string typed recipe content /// /// public string GetRecipeContentString() { if (string.IsNullOrEmpty(UserName)) { var dlg1 = new Aitex.UI.RecipeEditor.UserNameInput() { Owner = Application.Current.MainWindow }; var ret = dlg1.ShowDialog(); if (ret.HasValue && ret.Value) { UserName = dlg1.UserName; } } RecipeHead.LastRevisionTime = DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss"); RecipeHead.LastModifiedBy = UserName; InvokePropertyChanged("RecipeHead"); if (RecipeRows == null || RecipeRows.Count == 0 || RecipeRows[0].RecipeItems == null || RecipeRows[0].RecipeItems.Count == 0) return string.Empty; //Dictionary>> _recipeReadingFormat; XmlDocument doc = new XmlDocument(); var rootNode = doc.CreateElement("TableRecipeData"); rootNode.SetAttribute("RecipeVersion", RecipeHead.RecipeVariation); rootNode.SetAttribute("CreatedBy", RecipeHead.CreatedBy); rootNode.SetAttribute("CreationTime", RecipeHead.CreationTime); rootNode.SetAttribute("LastRevisedBy", RecipeHead.LastModifiedBy); rootNode.SetAttribute("LastRevisionTime", RecipeHead.LastRevisionTime); if (!string.IsNullOrEmpty(RecipeHead.PressureMode)) { rootNode.SetAttribute("PressureMode", RecipeHead.PressureMode); } if (!string.IsNullOrEmpty(RecipeHead.BasePressure)) { rootNode.SetAttribute("BasePressure", RecipeHead.BasePressure); } if (!string.IsNullOrEmpty(RecipeHead.SubstrateTemp)) { rootNode.SetAttribute("SubstrateTemp", RecipeHead.SubstrateTemp); } if (!string.IsNullOrEmpty(RecipeHead.PumpingPinState)) { rootNode.SetAttribute("PumpingPinState", RecipeHead.PumpingPinState); } if(!string.IsNullOrEmpty(RecipeHead.VentingPinState)) { rootNode.SetAttribute("VentingPinState", RecipeHead.VentingPinState); } if(!string.IsNullOrEmpty(RecipeHead.PinDownPressure)) { rootNode.SetAttribute("PinDownPressure", RecipeHead.PinDownPressure); } if (!string.IsNullOrEmpty(RecipeHead.PumpDownLimit)) { rootNode.SetAttribute("PumpDownLimit", RecipeHead.PumpDownLimit); } if (!string.IsNullOrEmpty(RecipeHead.PurgeActive)) { rootNode.SetAttribute("PurgeActive", RecipeHead.PurgeActive); } if (!string.IsNullOrEmpty(RecipeHead.NotToPurgeOrVent)) { rootNode.SetAttribute("NotToPurgeOrVent", RecipeHead.NotToPurgeOrVent); } rootNode.SetAttribute("Barcode", RecipeHead.Barcode); rootNode.SetAttribute("Description", RecipeHead.Description); doc.AppendChild(rootNode); for (int stepIndex/* 0-> */ = 0; stepIndex < RecipeRows[0].RecipeItems.Count; stepIndex++) { var stepNode = doc.CreateElement("Step"); rootNode.AppendChild(stepNode); foreach (var module in _recipeSavingFormat) { var moduleName = module.Key; XmlElement subNode = stepNode; if (!string.IsNullOrEmpty(moduleName)) { string[] pathArr = moduleName.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < pathArr.Length; i++) { var snd = subNode.SelectSingleNode(pathArr[i]) as XmlElement; if (snd == null) { var nd = doc.CreateElement(pathArr[i]); subNode.AppendChild(nd); subNode = nd; } else { subNode = snd; } } } foreach (var controlName in module.Value) { if (controlName == "StepNo") { subNode.SetAttribute(controlName, string.Format("第{0}步", stepIndex + 1)); } else { var recipeRow = RecipeRows.First((o) => o.TechnicalName == controlName); if (recipeRow == null) continue; /*to compatiable with old recipe editor, always fill 'black space' to loop step*/ if (controlName == "Loop" && string.IsNullOrEmpty(recipeRow.RecipeItems[stepIndex].Value)) subNode.SetAttribute(controlName, " "); else { subNode.SetAttribute(controlName, recipeRow.RecipeItems[stepIndex].Value); //bool isJump = recipeRow.RecipeItems[stepIndex].IsJump; //if (isJump) //{ // string deviceType = recipeRow.RecipeItems[stepIndex].RecipeVariableDefine.DeviceType; // if (deviceType == "MFC" || deviceType == "PC") // subNode.SetAttribute(controlName + ".IsJump", isJump.ToString()); //} } } } } } return doc.OuterXml; } private void RightClickAction() { //DataGridControl.ContextMenu = null; ////get selected column information //List selectedColumns = new List(); //foreach (var item in DataGridControl.SelectedCellRanges) //{ // bool dir = item.ColumnRange.StartIndex <= item.ColumnRange.EndIndex; // if (dir) // { // for (int i = item.ColumnRange.StartIndex; i <= item.ColumnRange.EndIndex; i++) // { // if (i > 0) // if (!selectedColumns.Contains(i)) selectedColumns.Add(i); // } // } // else // { // for (int i = item.ColumnRange.StartIndex; i >= item.ColumnRange.EndIndex; i--) // { // if (i > 0) // if (!selectedColumns.Contains(i)) selectedColumns.Add(i); // } // } //} //selectedColumns.Sort(); ////debug only ///* //string s = ""; //foreach (var item in selectedColumns) //{ // s += "," + item; //} //MessageBox.Show(s); // * */ ////generate context menu //ContextMenu cms = new ContextMenu(); //if (selectedColumns.Count > 0) //{ // string colStrings = ""; // foreach (var item in selectedColumns) // { // if (string.IsNullOrEmpty(colStrings)) // colStrings = item.ToString(); // else // colStrings += "," + item.ToString(); // } // MenuItem mi; // cms.Items.Add(new MenuItem() { Header = string.Format(" 当前选中第{0}步", colStrings), FontFamily = new FontFamily("Arial,SimSun"), IsEnabled = false, Background = Brushes.Gray, Foreground = Brushes.White }); // //copy // mi = new MenuItem() { Header = " 复制", FontFamily = new FontFamily("Arial,SimSun"), Tag = selectedColumns.ToList() }; // mi.Click += (s, e) => // { // try // { // var list = (s as MenuItem).Tag as List; // _copiedColumnDatas.Clear(); // foreach (var colId in list) // { // _copiedColumnDatas.Add(colId/*index from 1*/, new List()); // for (int i = 0; i < RecipeRows.Count; i++) // { // var oldCellData = RecipeRows[i].RecipeItems[colId - 1]; // var newCellData = new SmartCellData() { Value = oldCellData.Value, RecipeVariableDefine = oldCellData.RecipeVariableDefine }; // _copiedColumnDatas[colId].Add(newCellData); // } // } // } // catch (Exception ex) // { // System.Diagnostics.Debug.WriteLine(ex.Message); // } // }; // cms.Items.Add(mi); // if (selectedColumns.Count < RecipeRows[0].RecipeItems.Count) // { // mi = new MenuItem() { Header = " 剪切", FontFamily = new FontFamily("Arial,SimSun"), Tag = selectedColumns.ToList() }; // mi.Click += (s, e) => // { // try // { // AddUndoHistory("剪切", CloneRecipeRowData(RecipeRows)); // var list = (s as MenuItem).Tag as List; // _copiedColumnDatas.Clear(); // foreach (var colId in list) // { // _copiedColumnDatas.Add(colId/*index from 1*/, new List()); // for (int i = 0; i < RecipeRows.Count; i++) // { // var oldCellData = RecipeRows[i].RecipeItems[colId - 1]; // var newCellData = new SmartCellData() { Value = oldCellData.Value, RecipeVariableDefine = oldCellData.RecipeVariableDefine }; // _copiedColumnDatas[colId].Add(newCellData); // } // } // foreach (var item in RecipeRows) // { // var collection = new ObservableCollection(); // for (int index = 0; index < item.RecipeItems.Count; index++) // { // if (list.Contains(index + 1)) // continue; // collection.Add(item.RecipeItems[index]); // } // item.RecipeItems = collection; // } // RefreshDataGrid(); // RefreshCellsDisplay(false); // } // catch (Exception ex) // { // System.Diagnostics.Debug.WriteLine(ex.Message); // } // }; // cms.Items.Add(mi); // mi = new MenuItem() { Header = " 删除", FontFamily = new FontFamily("Arial,SimSun"), Tag = selectedColumns.ToList() }; // mi.Click += (s, e) => // { // try // { // AddUndoHistory("删除", CloneRecipeRowData(RecipeRows)); // var list = (s as MenuItem).Tag as List; // foreach (var item in RecipeRows) // { // var collection = new ObservableCollection(); // for (int index = 0; index < item.RecipeItems.Count; index++) // { // if (list.Contains(index + 1)) // continue; // collection.Add(item.RecipeItems[index]); // } // item.RecipeItems = collection; // } // RefreshDataGrid(); // RefreshCellsDisplay(false); // } // catch (Exception ex) // { // System.Diagnostics.Debug.WriteLine(ex.Message); // } // }; // cms.Items.Add(mi); // } // if (selectedColumns.Count == 1 && _copiedColumnDatas.Count > 0) // { // mi = new MenuItem() { Header = string.Format(" 插入第{0}步后", selectedColumns[0]/*, _copiedColumnDatas.Count*/), FontFamily = new FontFamily("Arial,SimSun"), Tag = selectedColumns[0] }; // mi.Click += (s, e) => // { // try // { // AddUndoHistory("插入", CloneRecipeRowData(RecipeRows)); // int insertColId = (int)(s as MenuItem).Tag; // for (int rowIndex = 0; rowIndex < RecipeRows.Count; rowIndex++) // { // var collection = new ObservableCollection(); // for (int index = 0; index < insertColId; index++) // { // collection.Add(RecipeRows[rowIndex].RecipeItems[index]); // } // foreach (var col in _copiedColumnDatas) // { // collection.Add(new SmartCellData() { Value = col.Value[rowIndex].Value, RecipeVariableDefine = col.Value[rowIndex].RecipeVariableDefine }); // } // for (int index = insertColId; index < RecipeRows[rowIndex].RecipeItems.Count; index++) // { // collection.Add(RecipeRows[rowIndex].RecipeItems[index]); // } // RecipeRows[rowIndex].RecipeItems = collection; // } // RefreshDataGrid(); // RefreshCellsDisplay(false); // } // catch (Exception ex) // { // System.Diagnostics.Debug.WriteLine(ex.Message); // } // }; // cms.Items.Add(mi); // } //} ////show context menu //DataGridControl.ContextMenu = cms; //cms.Visibility = Visibility.Visible; } /// /// Parse recipe content with recipe format /// /// /// /// public void LoadRecipe(string recipeFormat, string recipeContent, int selectedStepNo = -1) { DataGridVisibility = Visibility.Visible; RecipeModelObservableCollection = new ObservableCollection() { new RecipeModel() { Name = "Alex" } }; } /// /// 检查变量ramp rate /// /// /// /// /// /// /// /// False:check ok, True: check failed public bool CheckRampRate(int stepNo, string rampEnable, string varName, string rampTime, double maxRampUpRate, double maxRampDownRate) { try { if (stepNo <= 0) return false; int rowIndex = RowVarNameDic[varName]; double currentValue = double.Parse(RecipeRows[rowIndex].RecipeItems[stepNo].Value); //if (varName == "AZone.Setpoint" || varName == "BZone.Setpoint" || varName == "CZone.Setpoint" || varName == "DZone.Setpoint") //{ // int heatControlModeIndex = RowVarNameDic["Heater.Mode"]; // string curStepHeatCtrlMode = RecipeRows[heatControlModeIndex].RecipeItems[stepNo].Value; // string lastStepHeatCtrlMode = RecipeRows[heatControlModeIndex].RecipeItems[stepNo - 1].Value; // if (curStepHeatCtrlMode != lastStepHeatCtrlMode) // { // if (!(lastStepHeatCtrlMode.Equals("CurrentControl") && curStepHeatCtrlMode.Equals("PyroTempControl"))) // return false; // int endbyIndex = RowVarNameDic["EndBy"]; // int endValueIndex = RowVarNameDic["EndValue"]; // string endby = RecipeRows[endbyIndex].RecipeItems[stepNo - 1].Value; // EndByCondition endbyEnum; // if (!Enum.TryParse(endby, out endbyEnum)) return false; // if (endbyEnum != EndByCondition.PmTempGt && endbyEnum != EndByCondition.PmTempLt) return false; // string end = RecipeRows[endValueIndex].RecipeItems[stepNo - 1].Value; // double endValue; // if (!double.TryParse(end, out endValue)) return false; // return CheckRampRate(rampEnable, rampTime, maxRampUpRate, maxRampDownRate, endValue, currentValue); // } //} double prevValue = double.Parse(RecipeRows[rowIndex].RecipeItems[stepNo - 1].Value); return CheckRampRate(rampEnable, rampTime, maxRampUpRate, maxRampDownRate, prevValue, currentValue); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.Message); return true; } } bool CheckRampRate(string rampEnable, string rampTime, double maxRampUpRate, double maxRampDownRate, double prevValue, double currentValue) { bool isRampEnable = bool.Parse(rampEnable); //string[] timeStr = rampTime.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries); //string tt = string.Join(":", timeStr); TimeSpan timeSpan; TimeSpan.TryParse(rampTime, out timeSpan); double totalTimeSec = timeSpan.TotalSeconds; double diff = currentValue - prevValue; if (!isRampEnable || totalTimeSec <= 0) { if (diff != 0) return true; return false; } else { double rampRate = diff / totalTimeSec; return (rampRate > 0 && rampRate >= maxRampUpRate) || (rampRate < 0 && rampRate <= -maxRampDownRate); } } /// /// Refresh datagrid cell data display /// /// True: moving to current running step position public void RefreshCellsDisplay(bool moving2RunningStepPosition = true) { try { if (RecipeRows == null || RecipeRows.Count < 2) return; Errors = new List>(); Dictionary dicEndby = new Dictionary(); Dictionary dicPressureMode = new Dictionary(); Dictionary dicRfMode = new Dictionary(); Dictionary dicRfMatchProcessMode = new Dictionary(); Dictionary dicSetMatchPositionC1 = new Dictionary(); Dictionary dicSetMatchPositionC2 = new Dictionary(); for (int i = 0; i < RecipeRows.Count; i++) { for (int j = 0; j < RecipeRows[i].RecipeItems.Count; j++) { var cell = RecipeRows[i].RecipeItems[j]; cell.RowIndex = i; cell.ColIndex = j; cell.ErrInfo = string.Empty; bool logicEnable = true; if (cell.RecipeVariableDefine.TechnicalName == "EndBy") dicEndby[j] = cell.Value; if (cell.RecipeVariableDefine.TechnicalName == "ThrottleValve.SetMode") { dicPressureMode[j] = cell.Value; } if (cell.RecipeVariableDefine.TechnicalName == "PressureControl.SetTVMode") { dicPressureMode[j] = cell.Value; } if (cell.RecipeVariableDefine.TechnicalName == "Rf.SetMode") dicRfMode[j] = cell.Value; if (cell.RecipeVariableDefine.TechnicalName == "Match.SetMatchProcessMode") dicRfMatchProcessMode[j] = cell.Value; if (cell.RecipeVariableDefine.TechnicalName == "Match.SetMatchPositionC1") dicSetMatchPositionC1[j] = cell.Value; if (cell.RecipeVariableDefine.TechnicalName == "Match.SetMatchPositionC2") dicSetMatchPositionC2[j] = cell.Value; if (cell.RecipeVariableDefine.TechnicalName == "Time") { logicEnable = dicEndby.ContainsKey(j) && (dicEndby[j] == "EndByStepTime" || dicEndby[j] == "EndByHeatUp" || dicEndby[j] == "EndByEndPoint"); } if (cell.RecipeVariableDefine.TechnicalName == "ThrottleValve.SetPosition") { logicEnable = dicPressureMode.ContainsKey(j) && dicPressureMode[j] == "TVPositionCtrl"; } if (cell.RecipeVariableDefine.TechnicalName == "ThrottleValve.SetPressure") { logicEnable = dicPressureMode.ContainsKey(j) && dicPressureMode[j] == "TVPressureCtrl"; } if (cell.RecipeVariableDefine.TechnicalName == "PressureControl.SetTVPosition") { logicEnable = dicPressureMode.ContainsKey(j) && dicPressureMode[j] == "TVPositionCtrl"; } if (cell.RecipeVariableDefine.TechnicalName == "PressureControl.SetTVPressure") { logicEnable = dicPressureMode.ContainsKey(j) && dicPressureMode[j] == "TVPressureCtrl"; } if (cell.RecipeVariableDefine.TechnicalName == "Rf.SetPulsingFrequency") { logicEnable = dicRfMode.ContainsKey(j) && dicRfMode[j] == "PulsingMode"; } if (cell.RecipeVariableDefine.TechnicalName == "Rf.SetPulsingDuty") { logicEnable = dicRfMode.ContainsKey(j) && dicRfMode[j] == "PulsingMode"; } if (cell.RecipeVariableDefine.TechnicalName == "Rf.SetPowerOnTime") { logicEnable = dicEndby.ContainsKey(j) && dicEndby[j] == "EndByRfTime"; } if (cell.RecipeVariableDefine.TechnicalName == "EPD.SetConfig") { logicEnable = dicEndby.ContainsKey(j) && dicEndby[j] == "EndByEndPoint"; if (string.IsNullOrEmpty(cell.Value) || cell.Value.StartsWith("n/a")) cell.Value = _defaultEndPointValue; } if (cell.RecipeVariableDefine.TechnicalName == "Match.SetMatchProcessMode") { logicEnable = dicRfMatchProcessMode.ContainsKey(j);// && dicRfMatchProcessMode[j] == "TritonPresetMode"; } if (cell.RecipeVariableDefine.TechnicalName == "Match.SetMatchPositionC1") { logicEnable = dicSetMatchPositionC1.ContainsKey(j);// && dicRfMatchProcessMode[j] == "TritonPresetMode"; } if (cell.RecipeVariableDefine.TechnicalName == "Match.SetMatchPositionC2") { logicEnable = dicSetMatchPositionC2.ContainsKey(j);// && dicRfMatchProcessMode[j] == "TritonPresetMode"; } cell.IsMasked = !logicEnable; //update diff variable numbers if (cell.RecipeVariableDefine.TechnicalName == "Ramp") { //更新当前步骤中Ramp的变量数据 if (j == 0) { cell.Tag = 0; } else { int rampNum = 0; for (int s1 = 0; s1 < RecipeRows.Count; s1++) { if (RecipeRows[s1].CatalogName == "StepInfo")// RecipeRows[s1].RecipeItems[j].RecipeVariableDefine.CellType == CellType.ReadOnly) continue; string preValue = RecipeRows[s1].RecipeItems[j - 1].Value; string curValue = RecipeRows[s1].RecipeItems[j].Value; if (RecipeRows[s1].RecipeItems[j].RecipeVariableDefine.CellType == CellType.NumInput) { double pd, cd; if (double.TryParse(preValue, out pd) && double.TryParse(curValue, out cd)) if (pd != cd) rampNum++; } else if (String.Compare(preValue, curValue, false) != 0) { rampNum++; } } cell.Tag = rampNum; } cell.InvokePropertyChanged(); } #region mask (hide or show cell content) if ((MaskedTechNames != null && MaskedTechNames.Contains(cell.RecipeVariableDefine.TechnicalName)) || (MaskedCatalogNames != null && MaskedCatalogNames.Contains(cell.RecipeVariableDefine.CatalogName)) || !logicEnable) cell.IsMasked = true; else cell.IsMasked = false; #endregion mask (hide or show cell content) #region check cell data range switch (cell.RecipeVariableDefine.CellType) { case CellType.CheckBox: { if (string.Compare(cell.Value, "true", true) == 0 || string.Compare(cell.Value, "false", true) == 0) { cell.ErrInfo = ""; cell.Background = Brushes.Transparent; } else { string reason = string.Format("Value '{0}' not valid", cell.Value); Errors.Add(new Tuple(i, j, cell.RecipeVariableDefine.FriendlyName, reason)); cell.ErrInfo = reason; cell.Background = Brushes.Pink; } } break; case CellType.EditableSelection: { cell.ErrInfo = ""; cell.Background = Brushes.Transparent; } break; case CellType.NumInput: { double min = cell.RecipeVariableDefine.MinValue; double max = cell.RecipeVariableDefine.MaxValue; double v; if (!double.TryParse(cell.Value, out v)) { string reason = string.Format("Value '{0}' not valid", cell.Value); Errors.Add(new Tuple(i, j, cell.RecipeVariableDefine.FriendlyName, reason)); cell.ErrInfo = reason; cell.Background = Brushes.Pink; } else if (v > max || v < 0 || (v < min && v > max * 0.1 / 100)) { string reason = string.Format("Value'{0}',Out of Range {1}~{2}", cell.Value, min, max); Errors.Add(new Tuple(i, j, cell.RecipeVariableDefine.FriendlyName, reason)); cell.ErrInfo = reason; cell.Background = Brushes.Pink; } else { cell.ErrInfo = ""; cell.Background = Brushes.Transparent; } } break; case CellType.ReadOnlySelection: { if (cell.RecipeVariableDefine.DropdownItemList != null && cell.RecipeVariableDefine.DropdownItemList.Find((o) => o.Item1 == cell.Value) != null) { cell.ErrInfo = ""; cell.Background = Brushes.Transparent; } else { string reason = string.Format("Value'{0}' is not valid", cell.Value); Errors.Add(new Tuple(i, j, cell.RecipeVariableDefine.FriendlyName, reason)); cell.ErrInfo = reason; cell.Background = Brushes.Pink; } } break; case CellType.ReadOnly: case CellType.TextInput: cell.ErrInfo = ""; cell.Background = Brushes.Transparent; break; case CellType.TimeInput: { string[] arr = cell.Value.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries); int h, mi, s; 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) { cell.ErrInfo = ""; cell.Background = Brushes.Transparent; } else { string reason = string.Format("value'{0}' is not valid", cell.Value); Errors.Add(new Tuple(i, j, cell.RecipeVariableDefine.FriendlyName, reason)); cell.ErrInfo = reason; cell.Background = Brushes.Pink; } } break; } #endregion check cell data range #region mark data trend / hide same content if (j == 0) //step one { cell.Foreground = Brushes.Black; cell.FontWeight = FontWeights.Normal; cell.IsHidden = false; cell.InvokePropertyChanged(); cell.IsMasked = !logicEnable; continue; } var preCell = RecipeRows[i].RecipeItems[j - 1]; if (cell.RecipeVariableDefine.CellType == CellType.NumInput) { double preValue = 0; double.TryParse(preCell.Value.ToString(), out preValue); double curValue = 0; double.TryParse(cell.Value.ToString(), out curValue); if (curValue > preValue) { cell.Foreground = Brushes.Red; cell.FontWeight = FontWeights.Bold; } else if (curValue < preValue) { cell.Foreground = Brushes.Blue; cell.FontWeight = FontWeights.Bold; } else { cell.Foreground = Brushes.Black; cell.FontWeight = FontWeights.Normal; } } else { //not number type cell.Foreground = Brushes.Black; cell.FontWeight = FontWeights.Normal; } if (IsHideSameContent && cell.Value == preCell.Value) cell.IsHidden = true; else cell.IsHidden = false; //!logicEnable; cell.IsMasked = !logicEnable; //if (!logicEnable) //{ // cell.Background = Brushes.DarkGray; // cell.IsMasked = true; //} #endregion mark data trend / hide same content cell.InvokePropertyChanged(); } } #region check loop int loopRowId = -1; for (int i = 0; i < RecipeRows.Count; i++) { if (RecipeRows[i].TechnicalName == "Loop") { loopRowId = i; break; } } for (int j = 0; j < RecipeRows[loopRowId].RecipeItems.Count; j++) { var cell = RecipeRows[loopRowId].RecipeItems[j]; bool isLoopStart = Regex.IsMatch(cell.Value, @"^Loop\x20\d+$"); bool isLoopEnd = Regex.IsMatch(cell.Value, @"^Loop End$"); bool isNullOrEmpty = string.IsNullOrWhiteSpace(cell.Value); if (!isLoopEnd && !isLoopStart && !isNullOrEmpty) { string reason = string.Format("Value '{0}' not valid", cell.Value); cell.ErrInfo = reason; cell.Background = Brushes.Pink; Errors.Add(new Tuple(loopRowId, j, cell.RecipeVariableDefine.FriendlyName, reason)); } if (isLoopEnd) { string reason = "Loop Start 缺失"; cell.ErrInfo = reason; cell.Background = Brushes.Pink; Errors.Add(new Tuple(loopRowId, j, cell.RecipeVariableDefine.FriendlyName, reason)); } else if (isLoopStart) { for (int k = j + 1; k < RecipeRows[loopRowId].RecipeItems.Count; k++) { cell = RecipeRows[loopRowId].RecipeItems[k]; bool isCurStepLoopStart = Regex.IsMatch(cell.Value, @"^Loop\x20\d+$"); bool isCurStepLoopEnd = Regex.IsMatch(cell.Value, @"^Loop End$"); isNullOrEmpty = string.IsNullOrWhiteSpace(cell.Value); if (!isCurStepLoopEnd && !isCurStepLoopStart && !isNullOrEmpty) { string reason = string.Format("Value '{0}' not valid", cell.Value); cell.ErrInfo = reason; cell.Background = Brushes.Pink; Errors.Add(new Tuple(loopRowId, k, cell.RecipeVariableDefine.FriendlyName, reason)); } else if (isCurStepLoopStart) { string reason = "前面循环没有结束,不能设置新的Loop Start标志"; cell.ErrInfo = reason; cell.Background = Brushes.Pink; Errors.Add(new Tuple(loopRowId, k, cell.RecipeVariableDefine.FriendlyName, reason)); } else if (isCurStepLoopEnd) { //mark loop steps with blue background for (int m1 = j; m1 <= k; m1++) { var curCell = RecipeRows[loopRowId].RecipeItems[m1]; if (curCell.Background == Brushes.Transparent) curCell.Background = Brushes.LightGreen; curCell.InvokePropertyChanged(); } j = k; break; } if (k == RecipeRows[loopRowId].RecipeItems.Count - 1) { j = k; string reason = "Loop End 缺失"; cell.ErrInfo = reason; cell.Background = Brushes.Pink; Errors.Add(new Tuple(loopRowId, k, cell.RecipeVariableDefine.FriendlyName, reason)); } } } } #endregion check loop #region recipe parameter validation //using (var lua = new LuaInterface.Lua()) //{ // //is special recipe? // //bool IsSpecialRecipe = true; // //{ // // int heaterModeRowIndex = RowVarNameDic["Heater.Mode"]; // // int aZoneSetpointIndex = RowVarNameDic["AZone.Setpoint"]; // // int bZoneSetpointIndex = RowVarNameDic["BZone.Setpoint"]; // // int cZoneSetpointIndex = RowVarNameDic["CZone.Setpoint"]; // // int dZoneSetpointIndex = RowVarNameDic.ContainsKey("DZone.Setpoint") ? RowVarNameDic["DZone.Setpoint"] : aZoneSetpointIndex; // // for (int stepIndex = 0; stepIndex < RecipeRows[0].RecipeItems.Count; stepIndex++) // // { // // if (RecipeRows[heaterModeRowIndex].RecipeItems[stepIndex].Value != "CurrentControl" || // // RecipeRows[aZoneSetpointIndex].RecipeItems[stepIndex].Value != "0" || // // RecipeRows[bZoneSetpointIndex].RecipeItems[stepIndex].Value != "0" || // // RecipeRows[cZoneSetpointIndex].RecipeItems[stepIndex].Value != "0" || // // RecipeRows[dZoneSetpointIndex].RecipeItems[stepIndex].Value != "0") // // { // // IsSpecialRecipe = false; // // break; // // } // // } // //} // ////set get ramp rate function // //lua.RegisterFunction("CheckRampRate", this, GetType().GetMethod("CheckRampRate")); // //lua.DoString(string.Format("IsProductionRecipe={0};",(!IsSpecialRecipe).ToString().ToLower())); // for (int stepIndex = 0; stepIndex < RecipeRows[0].RecipeItems.Count; stepIndex++) // { // //set stepNo // lua.DoString(string.Format("StepNo={0};", stepIndex)); // //reading var from current recipe step // foreach (var checkVar in _checkVariables) // { // if (!RowVarNameDic.ContainsKey(checkVar)) // { // System.Diagnostics.Debug.WriteLine("检查不到变量定义," + checkVar); // continue; // } // try // { // int varId = RowVarNameDic[checkVar]; // if (RecipeRows[varId].RecipeItems[stepIndex].RecipeVariableDefine.CellType == CellType.NumInput) // lua.DoString(string.Format("{0}={1};", RecipeRows[varId].RecipeItems[stepIndex].RecipeVariableDefine.TechnicalName.Replace(".", "_"), RecipeRows[varId].RecipeItems[stepIndex].Value)); // else // lua.DoString(string.Format("{0}=\"{1}\";", RecipeRows[varId].RecipeItems[stepIndex].RecipeVariableDefine.TechnicalName.Replace(".", "_"), RecipeRows[varId].RecipeItems[stepIndex].Value)); // } // catch (Exception ex) // { // System.Diagnostics.Debug.WriteLine("校验异常," + ex); // } // } // //reading from recipe format file // foreach (string key in _preDefinedRecipeVars.Keys) // { // string varValueString = _preDefinedRecipeVars[key]; // double varValue; // if (double.TryParse(varValueString, out varValue)) // lua.DoString(string.Format("{0}={1};", key, varValue)); // else // lua.DoString(string.Format("{0}=\"{1}\";", key, varValueString)); // } // //do valation // foreach (var rule in _validationRules) // { // lua.DoString(string.Format("if {0} then hasErr=1 else hasErr=0 end", rule.Item2)); // bool hasError = ((int)lua.GetNumber("hasErr")) == 1; // if (hasError) // { // lua.DoString(string.Format("message=string.format({0});", rule.Item3)); // string reason = lua.GetString("message"); // var rowId = RowVarNameDic[rule.Item1]; // var cell = RecipeRows[rowId].RecipeItems[stepIndex]; // cell.ErrInfo = reason; // cell.Background = Brushes.Pink; // Errors.Add(new Tuple(rowId, stepIndex, cell.RecipeVariableDefine.FriendlyName, reason)); // cell.InvokePropertyChanged(); // } // } // } //} #endregion recipe parameter validation #region update material cell data int materialRowId = -1; for (int colId = 0; colId < RecipeRows[0].RecipeItems.Count; colId++) { string materialName = ""; for (int rowId = 0; rowId < RecipeRows.Count; rowId++) { string curMo = ""; if (materialRowId == -1 && RecipeRows[rowId].RecipeItems[colId].RecipeVariableDefine.TechnicalName == "Material") { materialRowId = rowId; } var cell = RecipeRows[rowId].RecipeItems[colId]; if (cell.RecipeVariableDefine.CellType == CellType.ReadOnlySelection && String.Compare(cell.Value, "flow", true) == 0) { string moName = cell.RecipeVariableDefine.TechnicalName.Split('.')[0].ToLower(); string displayName = cell.RecipeVariableDefine.FriendlyName.Replace("_", ".").Split('.')[0].ToLower(); if (moName.Contains("cp2mg_1") || displayName.Contains("cp2mg_1")) curMo = "Mg1"; else if (moName.Contains("cp2mg_2") || displayName.Contains("cp2mg_2")) curMo = "Mg2"; else if (moName.Contains("cp2mg_3") || displayName.Contains("cp2mg_3")) curMo = "Mg3"; else if (moName.Contains("cp2mg_4") || displayName.Contains("cp2mg_4")) curMo = "Mg4"; else if (moName.Contains("cp2mg") || displayName.Contains("cp2mg")) curMo = "Mg"; else if (moName.Contains("tmin") || displayName.Contains("tmin")) curMo = "In"; else if (moName.Contains("tmin_1") || displayName.Contains("tmin_1")) curMo = "In1"; else if (moName.Contains("tmin_2") || displayName.Contains("tmin_2")) curMo = "In2"; else if (moName.Contains("tmin_3") || displayName.Contains("tmin_3")) curMo = "In3"; else if (moName.Contains("tmin_4") || displayName.Contains("tmin_4")) curMo = "In4"; else if (moName.Contains("tmga") || displayName.Contains("tmga")) curMo = "TMG"; else if (moName.Contains("tmga_1") || displayName.Contains("tmga_1")) curMo = "TMG1"; else if (moName.Contains("tmga_2") || displayName.Contains("tmga_2")) curMo = "TMG2"; else if (moName.Contains("tmga_3") || displayName.Contains("tmga_3")) curMo = "TMG3"; else if (moName.Contains("tmga_4") || displayName.Contains("tmga_4")) curMo = "TMG4"; else if (moName.Contains("tega") || displayName.Contains("tega")) curMo = "TEG"; else if (moName.Contains("tega_1") || displayName.Contains("tega_1")) curMo = "TEG1"; else if (moName.Contains("tega_2") || displayName.Contains("tega_2")) curMo = "TEG2"; else if (moName.Contains("tega_3") || displayName.Contains("tega_3")) curMo = "TEG3"; else if (moName.Contains("tega_4") || displayName.Contains("tega_4")) curMo = "TEG4"; else if (moName.Contains("tmal") || displayName.Contains("tmal")) curMo = "TAl"; else if (moName.Contains("tmal_1") || displayName.Contains("tmal_1")) curMo = "TAl1"; else if (moName.Contains("tmal_2") || displayName.Contains("tmal_2")) curMo = "TAl2"; else if (moName.Contains("tmal_3") || displayName.Contains("tmal_3")) curMo = "TAl3"; else if (moName.Contains("tmal_4") || displayName.Contains("tmal_4")) curMo = "TAl4"; else if (moName.Contains("nh3source") || displayName.Contains("nh3source")) curMo = "NH3"; else if (moName.Contains("si")) curMo = "Si"; if (!string.IsNullOrEmpty(curMo)) { if (string.IsNullOrEmpty(materialName)) materialName = curMo; else materialName += "|" + curMo; } } } if (materialRowId >= 0) { RecipeRows[materialRowId].RecipeItems[colId].Value = materialName; RecipeRows[materialRowId].RecipeItems[colId].InvokePropertyChanged(); } } #endregion update material cell data #region update column header //if (DataGridControl.Columns.Count - 1 == RecipeRows[0].RecipeItems.Count) //{ // var redColHeader = (DataTemplate)DataGridControl.FindResource("columnRedTitleTemplate"); // var blackColHeader = (DataTemplate)DataGridControl.FindResource("columnBlackTitleTemplate"); // for (int j = 0; j < RecipeRows[0].RecipeItems.Count; j++) // { // DataGridControl.Columns[j + 1].Title = string.Format("{0}|{2}\r\n{1}", j + 1, RecipeRows[0].RecipeItems[j].Value, RecipeRows[2].RecipeItems[j].Value); // if (Errors.Find((o) => o.Item2 == j) != null) // DataGridControl.Columns[j + 1].TitleTemplate = redColHeader; // else // DataGridControl.Columns[j + 1].TitleTemplate = blackColHeader; // } //} #endregion update column header #region if running state, highlight current running step, move horizontal bar to current running step if (CurrentRunningStepNo > 0 && DataGridControl.Columns.Count > 2) { for (int rowId = 0; rowId < RecipeRows.Count; rowId++) { for (int colId = 0; colId < RecipeRows[0].RecipeItems.Count; colId++) { var cell = RecipeRows[rowId].RecipeItems[colId]; if (colId + 1 == CurrentRunningStepNo) { cell.IsRunning = true; } else { cell.IsRunning = false; } cell.InvokePropertyChanged("IsRunning"); } } //if (moving2RunningStepPosition) //{ // Task.Factory.StartNew(() => // { // System.Threading.Thread.Sleep(200); // DataGridControl.Dispatcher.Invoke(new Action(() => // { // double singleWidth = DataGridControl.Columns[1].Width; // double horizontalOffset = (CurrentRunningStepNo - 2) * singleWidth; // if (DataGridControl.ScrollViewer != null) // { // if (horizontalOffset > DataGridControl.ScrollViewer.ScrollableWidth) // horizontalOffset = DataGridControl.ScrollViewer.ScrollableWidth; // if (horizontalOffset < 0) // horizontalOffset = 0; // DataGridControl.ScrollViewer.ScrollToHorizontalOffset(horizontalOffset); // } // })); // }); //} } #endregion if running state, highlight current running step, move horizontal bar to current running step //calc recipe time CalcRecipeTime(); //invoke property InvokePropertyChanged("Errors"); } catch (Exception ex) { MessageBox.Show("工艺程序校验出错!\r\n\r\n" + ex.Message, "出错", MessageBoxButton.OK, MessageBoxImage.Error); System.Diagnostics.Debug.WriteLine(ex.Message); } } /// /// reload datagrid content /// private void RefreshDataGrid() { //try //{ //generate columns in Grid DataGridControl.CurrentColumn = null; if (DataGridControl.Columns.Count > 0) DataGridControl.Columns.Clear(); var template = (DataTemplate)DataGridControl.FindResource("CustomTemplate"); var rowTemplate = (DataTemplate)DataGridControl.FindResource("RowHeadTemplate"); //DataGridControl.Columns.Add(new Xceed.Wpf.DataGrid.Column() //{ // Width = 140, // Title = " ", // FieldName = ".", // CellContentTemplate = rowTemplate //}); // var cellEditor = DataGridControl.DefaultCellEditors[typeof(SmartCellData)];// DefaultCellEditorSelector.SelectCellEditor(typeof(SmartCellData)); // for (int index = 0; index < RecipeRows[0].RecipeItems.Count; index++) // { // //var col = new Xceed.Wpf.DataGrid.Column(); // DataGridControl.Columns.Add(new Xceed.Wpf.DataGrid.Column() // { // Title = string.Format("【{0}】\r\n{1}", index + 1, RecipeRows[0].RecipeItems[index].Value), // FieldName = string.Format("RecipeItems[{0}]", index), // CellContentTemplate = template, // AllowSort = false, // Width = 120, // MaxWidth = 120, // CellEditor = cellEditor // }); // } // InvokePropertyChanged("RecipeRows"); // InvokePropertyChanged("RecipeHead"); //} //catch (Exception ex) //{ // System.Diagnostics.Debug.WriteLine(ex.Message); //} } /// /// calc recipe total time /// private void CalcRecipeTime() { int timeStepRowId = -1; int loopStepRowId = -1; for (int i = 0; i < RecipeRows.Count; i++) { if (RecipeRows[i].TechnicalName == "Time") timeStepRowId = i; if (RecipeRows[i].TechnicalName == "Loop") loopStepRowId = i; if (loopStepRowId != -1 && timeStepRowId != -1) break; } TimeSpan tspan = new TimeSpan(); for (int stepNo = 0; stepNo < RecipeRows[timeStepRowId].RecipeItems.Count; stepNo++) { string loopStr = RecipeRows[loopStepRowId].RecipeItems[stepNo].Value; bool isLoopStart = Regex.IsMatch(loopStr, @"^Loop\x20\d+$"); if (isLoopStart) { int loopNum = int.Parse(loopStr.ToLower().Replace("loop", "").Replace(" ", "")); TimeSpan ts = new TimeSpan(); for (int innerStepNo = stepNo; innerStepNo < RecipeRows[timeStepRowId].RecipeItems.Count; innerStepNo++) { loopStr = RecipeRows[loopStepRowId].RecipeItems[innerStepNo].Value; stepNo = innerStepNo; string timeDuration = RecipeRows[timeStepRowId].RecipeItems[innerStepNo].Value; string[] timeArr = timeDuration.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries); if (timeArr.Length == 3) { int h, mi, s; if (int.TryParse(timeArr[0], out h) && int.TryParse(timeArr[1], out mi) && int.TryParse(timeArr[2], out s)) { var tt = new TimeSpan(h, mi, s); ts += tt; } } bool isLoopEnd = Regex.IsMatch(loopStr, @"^Loop End$"); if (isLoopEnd) { tspan += new TimeSpan(ts.Ticks * loopNum); break; } } } else { string timeDuration = RecipeRows[timeStepRowId].RecipeItems[stepNo].Value; string[] timeArr = timeDuration.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries); if (timeArr.Length == 3) { int h, mi, s; if (int.TryParse(timeArr[0], out h) && int.TryParse(timeArr[1], out mi) && int.TryParse(timeArr[2], out s)) { var ts = new TimeSpan(h, mi, s); tspan += ts; } } } } RecipeInfo = string.Format("共{0}步,总时间{1}:{2}:{3}", RecipeRows[0].RecipeItems.Count, (int)tspan.TotalHours, tspan.Minutes.ToString("00"), tspan.Seconds.ToString("00")); InvokePropertyChanged("RecipeInfo"); } #region INotifyPropertyChanged public event PropertyChangedEventHandler PropertyChanged; public void InvokePropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } #endregion INotifyPropertyChanged } public class RecipeRow { private ObservableCollection _recipeItems = new ObservableCollection(); public RecipeRow(params SmartCellData[] vars) { foreach (var var in vars) _recipeItems.Add(var); } public string CatalogName { get; set; } public string FriendlyName { get; set; } public string TechnicalName { get; set; } public ObservableCollection RecipeItems { get { return _recipeItems; } set { _recipeItems = value; } } } /// /// Recipe head /// public class RecipeHead { public string RecipeVariation { get; set; } public string CreationTime { get; set; } public string LastRevisionTime { get; set; } public string CreatedBy { get; set; } public string LastModifiedBy { get; set; } public string PressureMode { get; set; } public string Description { get; set; } public string BasePressure { get; set; } public string PumpDownLimit { get; set; } public string PurgeActive { get; set; } public string NotToPurgeOrVent { get; set; } public string Barcode { get; set; } public string SubstrateTemp { get; set; } public string PumpingPinState { get; set; } public string VentingPinState { get; set; } public string PinDownPressure { get; set; } } public class EndPointConfigItem : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public void InvokePropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } public string ExposureTime { get; set; } public string WaveLengthA { get; set; } public string BinningA { get; set; } public string WaveLengthB { get; set; } public string BinningB { get; set; } public string WaveLengthC { get; set; } public string BinningC { get; set; } public string WaveLengthD { get; set; } public string BinningD { get; set; } public string Fd { get; set; } public string PrefilterTime { get; set; } public string PostfilterTime { get; set; } public string AlgorithmType { get; set; } public string Criteria { get; set; } public string DelayTime { get; set; } public string ValidationTime { get; set; } public string ValidationValue { get; set; } public string TimeWindow { get; set; } public string MinimalTime { get; set; } public string PostponeTime { get; set; } public bool Control { get; set; } public bool Normalization { get; set; } public bool EnablePostponePercent { get; set; } public bool EnableCriterialPercent { get; set; } public bool EnableEventTrigger { get; set; } public bool IsFaultIfNoTrigger { get; set; } public string ToValue() { return $@"ExposureTime={ExposureTime};WaveLengthA={WaveLengthA};BinningA={BinningA};WaveLengthB={WaveLengthB};" + $@"BinningB={BinningB};WaveLengthC={WaveLengthC};BinningC={BinningC};WaveLengthD={WaveLengthD};BinningD={BinningD};Fd={Fd};" + $@"PrefilterTime={PrefilterTime};PostfilterTime={PostfilterTime};AlgorithmType={AlgorithmType};Criteria={Criteria};DelayTime={DelayTime};ValidationTime={ValidationTime};" + $@"ValidationValue={ValidationValue};TimeWindow={TimeWindow};MinimalTime={MinimalTime};PostponeTime={PostponeTime};Control={Control};Normalization={Normalization};" + $@"EnablePostponePercent={EnablePostponePercent};EnableCriterialPercent={EnableCriterialPercent};EnableEventTrigger={EnableEventTrigger};IsFaultIfNoTrigger={IsFaultIfNoTrigger};" ; } public void SetValue(string config) { if (string.IsNullOrEmpty(config)) return; string[] items = config.Split(';'); foreach (var item in items) { if (string.IsNullOrEmpty(item)) continue; string[] pairs = item.Split('='); if (pairs.Length != 2) continue; Parallel.ForEach(this.GetType().GetProperties(), property => { PropertyInfo pi = (PropertyInfo) property; if (pi.Name == pairs[0]) { try { var convertedValue = Convert.ChangeType(pairs[1], pi.PropertyType); var originValue = Convert.ChangeType(pi.GetValue(this, null), pi.PropertyType); if (originValue != convertedValue) { pi.SetValue(this, convertedValue, null); } } catch (Exception) { } } }); } } } }