using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms.VisualStyles; using System.Xml.Schema; using System.Xml; using System.IO; using Aitex.Core.RT.Log; using System.Text.RegularExpressions; using Aitex.Common.Util; using Aitex.Core.RT.Event; using Aitex.Core.Util; using Aitex.Core.Utilities; using Aitex.Core.WCF; using MECF.Framework.Common.OperationCenter; using MECF.Framework.Common.Properties; using MECF.Framework.Common.RecipeCenter; using System.Collections.ObjectModel; using Aitex.Core.RT.SCCore; using MECF.Framework.Common.DataCenter; using MECF.Framework.Common.ParameterCenter; using System.Linq; using MECF.Framework.Common.CommonData; namespace Aitex.Core.RT.ParameterCenter { public class ParameterFileManager : Singleton { //Recipe文件 统一放在 Recipes 文件夹下面 public const string SourceModule = "Parameter"; string _chamberId; private bool _recipeIsValid; private List _validationErrors = new List(); private List _validationWarnings = new List(); private Dictionary> _parameterItems; IParameterFileContext _rcpContext; public ParameterFileManager() { _chamberId = SC.GetStringValue("System.EditParameter.EditChamberType"); if (_chamberId == null) _chamberId = "Parameter"; } public void Initialize(IParameterFileContext context) { Initialize(context, true); } public void Initialize(IParameterFileContext rcpContext, bool enableService) { _rcpContext = rcpContext == null ? new DefaultParameterFileContext() : rcpContext; CultureSupported.UpdateCoreCultureResource(CultureSupported.English); if (enableService) { Singleton.Instance.Initialize(new Type[] { typeof(ParameterService) }); } var dir = string.Format("{0}{1}\\", PathManager.GetParameterDir(), ""); DirectoryInfo di = new DirectoryInfo(dir); if (!di.Exists) { di.Create(); } } private void ValidationEventHandler(object sender, ValidationEventArgs e) { switch (e.Severity) { case XmlSeverityType.Error: _validationErrors.Add(e.Message); _recipeIsValid = false; break; case XmlSeverityType.Warning: _validationWarnings.Add(e.Message); break; } } /// /// XML schema checking /// /// /// /// /// /// public bool ValidateParameter(string chamberId, string parameterName, string parameterContent, out List reason) { try { XmlDocument document = new XmlDocument(); document.LoadXml(parameterContent); MemoryStream schemaStream = new MemoryStream(ASCIIEncoding.ASCII.GetBytes(GetParameterSchema(chamberId))); XmlReader xmlSchemaReader = XmlReader.Create(schemaStream); XmlSchema schema1 = XmlSchema.Read(xmlSchemaReader, ValidationEventHandler); document.Schemas.Add(schema1); document.LoadXml(parameterContent); ValidationEventHandler eventHandler = new ValidationEventHandler(ValidationEventHandler); _recipeIsValid = true; _validationErrors = new List(); _validationWarnings = new List(); // Validates recipe. document.Validate(eventHandler); } catch (Exception ex) { LOG.Write(ex.Message); _recipeIsValid = false; } if (!_recipeIsValid && _validationErrors.Count == 0) { _validationErrors.Add(Resources.RecipeFileManager_ValidateRecipe_XMLSchemaValidateFailed); } reason = _validationErrors; return _recipeIsValid; } public bool GetParameterChecked(string chamberId, string parameterName) { string chamberType = chamberId.Split('\\')[0]; string processType = chamberId.Split('\\')[1]; string parameterContent = LoadParameter(chamberId, parameterName, false); var xmlParameter = new XmlDocument(); try { if (string.IsNullOrEmpty(parameterContent)) throw new Exception("invalid Parameter file."); xmlParameter.LoadXml(parameterContent); XmlNodeList nodeSteps = xmlParameter.SelectNodes($"Aitex/TableParameterData/Module[@Name='{processType}']/Step"); XmlNode nodeConfig = xmlParameter.SelectNodes($"Aitex/TableParameterData/Config")[0]; foreach (var item in nodeSteps) { XmlElement step = item as XmlElement; string strModuleName = step.Attributes["ModuleName"]?.Value; if (string.IsNullOrEmpty(strModuleName)) continue; if (!string.IsNullOrEmpty(strModuleName)) { string[] temp = strModuleName.Split(',')[0].Split(' '); if (temp.Length > 1) strModuleName = temp[1]; } else continue; if (ovenModuleName.Contains(strModuleName)) strModuleName = "Oven"; string linkParameterName = step.Attributes["ParameterName"]?.Value; if (string.IsNullOrEmpty(linkParameterName)) continue; string[] subParameterNames = linkParameterName.Split(','); foreach (var subItem in subParameterNames) { string subParameterName = string.Empty; string[] subParameterNameStrings = subItem.Split(':'); if (subParameterNameStrings.Length > 1) { subParameterName = subParameterNameStrings[1]; } else { subParameterName = subParameterNameStrings[0]; } if (!GetParameterChecked($"{_chamberId}\\{strModuleName}", subParameterName)) { return false; } } } //check system Parameter string strSystemParameterName = nodeConfig.Attributes["SystemParameter"]?.Value; if (!string.IsNullOrEmpty(strSystemParameterName)) { if (!GetParameterChecked($"{_chamberId}\\System", strSystemParameterName)) { return false; } } XmlElement nodeData = xmlParameter.SelectSingleNode($"Aitex/TableParameterData") as XmlElement; string checkResult = nodeData.Attributes["CheckResult"].Value; if (string.IsNullOrEmpty(checkResult)) return false; else return true; } catch (Exception ex) { LOG.Write(ex); return false; } } /// /// Check recipe content /// /// /// /// /// public bool CheckParameter(string chamberId, string parameterName, out List reasons) { reasons = new List(); string chamberType = chamberId.Split('\\')[0]; string processType = chamberId.Split('\\')[1]; string parameterContent = LoadParameter(chamberId, parameterName, false); var xmlParameter = new XmlDocument(); try { if (string.IsNullOrEmpty(parameterContent)) throw new Exception("invalid Parameter file."); xmlParameter.LoadXml(parameterContent); XmlNodeList nodeSteps = xmlParameter.SelectNodes($"Aitex/TableParameterData/Module[@Name='{processType}']/Step"); XmlNode nodeConfig = xmlParameter.SelectNodes($"Aitex/TableParameterData/Config")[0]; } catch (Exception ex) { reasons.Add(ex.Message); LOG.Write(ex); return false; } XmlElement nodeData = xmlParameter.SelectSingleNode($"Aitex/TableParameterData") as XmlElement; bool bResult = reasons.Count == 0; if (bResult) { nodeData.SetAttribute("CheckResult", "Correct"); } else { nodeData.SetAttribute("CheckResult", "Error"); } SaveParameter(chamberId, parameterName, xmlParameter.OuterXml, false, false); return bResult; } /// /// Check recipe content /// /// /// /// /// public bool CheckRestoreParameter(string chamberId, string parameterName, out List reasons) { reasons = new List(); string chamberType = chamberId.Split('\\')[0]; string processType = chamberId.Split('\\')[1]; string recipeContent = LoadRestoreParameter(chamberId, parameterName, false); var xmlRecipe = new XmlDocument(); try { if (string.IsNullOrEmpty(recipeContent)) throw new Exception("invalid recipe file."); xmlRecipe.LoadXml(recipeContent); XmlNodeList nodeSteps = xmlRecipe.SelectNodes($"Aitex/TableParameterData/Module[@Name='{processType}']/Step"); XmlNode nodeConfig = xmlRecipe.SelectNodes($"Aitex/TableParameterData/Config")[0]; } catch (Exception ex) { reasons.Add(ex.Message); LOG.Write(ex); return false; } XmlElement nodeData = xmlRecipe.SelectSingleNode($"Aitex/TableParameterData") as XmlElement; bool bResult = reasons.Count == 0; if (bResult) { nodeData.SetAttribute("CheckResult", "Correct"); } else { nodeData.SetAttribute("CheckResult", "Error"); } SaveRestoreParameter(chamberId, parameterName, xmlRecipe.OuterXml, false, false); return bResult; } /// /// This method will be invoked by two places: /// (1) Load a recipe from server to GUI for editing (do not need validation when loading, do validation when saving); /// (2) Load a recipe from recipe engine to run process(always do a validation before run recipe); /// /// /// indicate whether a recipe format validation is needed or not /// public string LoadParameter(string chamberId, string parameterName, bool needValidation) { string rcp = string.Empty; try { using (StreamReader fs = new StreamReader(GenerateParameterFilePath(chamberId, parameterName))) { rcp = fs.ReadToEnd(); fs.Close(); } //if (needValidation) //{ // List reason; // if (!ValidateRecipe(chamberId, recipeName, rcp, out reason)) // { // rcp = string.Empty; // LOG.Write("校验recipe file 出错, " + string.Join(",", reason.ToArray())); // } //} } catch (Exception ex) { LOG.Write(ex, $"load recipe file failed, {parameterName}"); rcp = string.Empty; } return rcp; } /// /// Get recipe list /// /// /// /// public IEnumerable GetParameters(string chamberId, bool includingUsedRecipe) { return _rcpContext.GetParameters(chamberId, includingUsedRecipe); } /// /// Get recipe list in xml format /// /// /// /// public string GetXmlParameterList(string chamberId, bool includingUsedParameter) { XmlDocument doc = new XmlDocument(); var baseFolderPath = getParameterDirPath(chamberId); DirectoryInfo curFolderInfo = new DirectoryInfo(baseFolderPath); doc.AppendChild(GenerateParameterList(chamberId, curFolderInfo, doc, includingUsedParameter)); return doc.OuterXml; } public void SaveParameterHistory(string chamberId, string parameterName, string parameterContent, bool needSaveAs = true) { try { if (!string.IsNullOrEmpty(parameterName) && needSaveAs) { string newRecipeName = string.Format("HistoryParameter\\{0}\\{1}", DateTime.Now.ToString("yyyyMM"), parameterName); SaveParameter(chamberId, newRecipeName, parameterContent, true, false); LOG.Write(string.Format("{0}通知TM保存工艺程序{1}", chamberId, parameterName)); } } catch (Exception ex) { LOG.Write(ex, string.Format("保存{0}工艺程序{1}发生错误", chamberId, parameterName)); } } /// /// generate recipe list information in current directory /// /// /// /// /// XmlElement GenerateParameterList(string chamberId, DirectoryInfo currentDir, XmlDocument doc, bool includingUsedParameter) { int trimLength = getParameterDirPath(chamberId).Length; XmlElement folderEle = doc.CreateElement("Folder"); folderEle.SetAttribute("Name", currentDir.FullName.Substring(trimLength)); DirectoryInfo[] dirInfos = currentDir.GetDirectories(); foreach (DirectoryInfo dirInfo in dirInfos) { if (!includingUsedParameter && dirInfo.Name == "HistoryParameter") continue; folderEle.AppendChild(GenerateParameterList(chamberId, dirInfo, doc, includingUsedParameter)); } FileInfo[] fileInfos = currentDir.GetFiles("*.rcp"); foreach (FileInfo fileInfo in fileInfos) { XmlElement fileNd = doc.CreateElement("File"); string fileStr = fileInfo.FullName.Substring(trimLength).TrimStart(new char[] { '\\' }); ; fileStr = fileStr.Substring(0, fileStr.LastIndexOf(".")); fileNd.SetAttribute("Name", fileStr); folderEle.AppendChild(fileNd); } return folderEle; } XmlElement GeneratelRestoreParameterList(string chamberId, DirectoryInfo currentDir, XmlDocument doc, bool includingUsedRecipe) { int trimLength = getParameterBackupDirPath(chamberId).Length; XmlElement folderEle = doc.CreateElement("Folder"); var name = currentDir.FullName.Substring(trimLength); folderEle.SetAttribute("Name", name); DirectoryInfo[] dirInfos = currentDir.GetDirectories(); foreach (DirectoryInfo dirInfo in dirInfos) { if (!includingUsedRecipe && dirInfo.Name == "HistoryParameter") continue; folderEle.AppendChild(GeneratelRestoreParameterList(chamberId, dirInfo, doc, includingUsedRecipe)); } FileInfo[] fileInfos = currentDir.GetFiles("*.rcp"); foreach (FileInfo fileInfo in fileInfos) { XmlElement fileNd = doc.CreateElement("File"); string fileStr = fileInfo.FullName.Substring(trimLength).TrimStart(new char[] { '\\' }); ; fileStr = fileStr.Substring(0, fileStr.LastIndexOf(".")); fileNd.SetAttribute("Name", fileStr); folderEle.AppendChild(fileNd); } return folderEle; } /// /// Delete a recipe by recipe name /// /// /// /// public bool DeleteParameter(string chamberId, string parameterName) { try { File.Delete(GenerateParameterFilePath(chamberId, parameterName)); EventInfo(string.Format(Resources.RecipeFileManager_DeleteRecipe_RecipeFile0DeleteSucceeded, parameterName)); } catch (Exception ex) { LOG.Write(ex, "删除recipe file 出错"); EventWarning(string.Format(Resources.RecipeFileManager_DeleteRecipe_RecipeFile0DeleteFailed, parameterName)); return false; } return true; } /// /// Rename recipe /// /// /// /// /// public bool RenameParameter(string chamId, string oldName, string newName) { try { if (File.Exists(GenerateParameterFilePath(chamId, newName))) { EventWarning(string.Format(Resources.RecipeFileManager_RenameRecipe_RecipeFile0FileExisted, oldName)); return false; } else { File.Move(GenerateParameterFilePath(chamId, oldName), GenerateParameterFilePath(chamId, newName)); EventInfo(string.Format(Resources.RecipeFileManager_RenameRecipe_RecipeFile0Renamed, oldName, newName)); } } catch (Exception ex) { LOG.Write(ex, "重命名recipe file 出错"); EventWarning(string.Format(Resources.RecipeFileManager_RenameRecipe_RecipeFile0RenameFailed, oldName, newName)); return false; } return true; } private static string ovenModuleName = "CPL,HHP,LHP,CHP,TCP"; private string[] ovenModuleNames = ovenModuleName.Split(','); private void UpdateCheckResult(string parameterName) { var xmlRecipe = new XmlDocument(); using (StreamReader fs = new StreamReader(parameterName)) { string parameterContent = fs.ReadToEnd(); fs.Close(); xmlRecipe.LoadXml(parameterContent); } XmlNode nodeConfig = xmlRecipe.SelectNodes($"Aitex/TableParameterData")[0]; nodeConfig.Attributes["CheckResult"].Value = string.Empty; XmlTextWriter writer = new XmlTextWriter(parameterName, Encoding.UTF8); writer.Formatting = Formatting.Indented; xmlRecipe.Save(writer); writer.Close(); } public bool BackupParameter(string fileOriginalPath, string fileDestinationPath, bool isSaveLinkParameter, List parameterNames) { try { } catch (Exception ex) { LOG.Write(ex, "Backup Recipe file error"); } return true; } public bool CheckBackParameterIsLinkParameter(string fileOriginalPath, List parameterNames) { string chamberType = fileOriginalPath.Split('\\')[0]; string processType = fileOriginalPath.Split('\\')[1]; foreach (var item in parameterNames) { string parameterContent = LoadParameter(fileOriginalPath, item, false); var xmlParameter = new XmlDocument(); try { if (string.IsNullOrEmpty(parameterContent)) continue; xmlParameter.LoadXml(parameterContent); XmlNodeList nodeSteps = xmlParameter.SelectNodes($"Aitex/TableParameterData/Module[@Name='{processType}']/Step"); XmlNode nodeConfig = xmlParameter.SelectNodes($"Aitex/TableParameterData/Config")[0]; switch (processType) { case "WaferFlow": foreach (var step in nodeSteps) { XmlElement nodestep = step as XmlElement; string strModuleName = nodestep.Attributes["ModuleName"]?.Value; if (string.IsNullOrEmpty(strModuleName)) { continue; } var linkRecipeName = nodestep.Attributes["RecipeName"].Value; if (string.IsNullOrEmpty(linkRecipeName)) { continue; } else { return true; } } string strSystemReicpeName = nodeConfig.Attributes["SystemRecipe"]?.Value; if (!string.IsNullOrEmpty(strSystemReicpeName)) { return true; } break; case "COT": case "DEV": string pumpRecipeName = nodeConfig.Attributes["COTPumpRecipe"]?.Value; if (!string.IsNullOrEmpty(pumpRecipeName)) { return true; } break; case "Dummy": foreach (var step in nodeSteps) { XmlElement nodestep = step as XmlElement; string regularSequence = nodestep.Attributes["RegularSequence"]?.Value; string preSequence = nodestep.Attributes["PreSequence"]?.Value; if (!string.IsNullOrEmpty(regularSequence)) { string[] regularSequences = regularSequence.Split(';'); foreach (var subItem in regularSequences) { if (string.IsNullOrEmpty(subItem)) continue; var pumpRecipe = GetKeyValue(subItem, "PumpRecipe"); if (!string.IsNullOrEmpty(pumpRecipe)) return true; } } if (!string.IsNullOrEmpty(preSequence)) { string[] preSequences = preSequence.Split(';'); foreach (var subItem in preSequences) { if (string.IsNullOrEmpty(subItem)) continue; var pumpRecipe = GetKeyValue(subItem, "PumpRecipe"); if (!string.IsNullOrEmpty(pumpRecipe)) return true; } } } break; case "Wash": foreach (var step in nodeSteps) { XmlElement nodestep = step as XmlElement; string sequence = nodestep.Attributes["Sequence"]?.Value; if (string.IsNullOrEmpty(sequence)) { continue; } var subSequences = sequence.Split(';'); foreach (var subSeq in subSequences) { if (string.IsNullOrEmpty(subSeq)) { continue; } var pumpRecipe = GetKeyValue(subSeq, "PumpRecipe"); if (!string.IsNullOrEmpty(subSeq)) { return true; } } } break; case "ADH": case "Oven": break; } } catch (Exception ex) { LOG.Write(ex); return false; } } return false; } private static string GetKeyValue(string args, string name) { string indexString = $"{name}="; string subString = args.Substring(args.IndexOf(indexString) + indexString.Length); int endIndex = subString.IndexOf(','); if (endIndex > 0) return subString.Substring(0, endIndex); else return subString; } public string GetXmlRestoreParameterList(string chamberId, bool includingUsedParameter) { XmlDocument doc = new XmlDocument(); var baseFolderPath = getParameterBackupDirPath(chamberId); DirectoryInfo curFolderInfo = new DirectoryInfo(baseFolderPath); doc.AppendChild(GeneratelRestoreParameterList(chamberId, curFolderInfo, doc, includingUsedParameter)); return doc.OuterXml; } public List RestoreParameterFolderList() { List folderList = new List(); var parameterBackupPath = PathManager.GetParameterBackupDir(); DirectoryInfo directoryInfo = new DirectoryInfo(parameterBackupPath); DirectoryInfo[] directoryInfos = directoryInfo.GetDirectories(); foreach (var item in directoryInfos) { folderList.Add(item.Name); } return folderList; } public string LoadRestoreParameter(string chamberId, string parameterName, bool needValidation) { string rcp = string.Empty; try { using (StreamReader fs = new StreamReader(GenerateBackupParameterFilePath(chamberId, parameterName))) { rcp = fs.ReadToEnd(); fs.Close(); } } catch (Exception ex) { LOG.Write(ex, $"load recipe file failed, {parameterName}"); rcp = string.Empty; } return rcp; } public bool SigRestoreParameter(string chamId, List parameterNames) { try { string filePath = getParameterBackupDirPath(chamId); foreach (var item in parameterNames) { string strdest = chamId; string destFilePath = GenerateParameterFilePath(strdest, item); string sourceFilePath = GenerateBackupParameterFilePath(chamId, item); if (item.Contains("\\")) { DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(destFilePath)); if (!di.Exists) di.Create(); } File.Copy(sourceFilePath, destFilePath, true); } } catch (Exception ex) { LOG.Write(ex, "Backup Recipe file error"); } return true; } private static Dictionary> CreateRestoreDirectory = new Dictionary>(); private string RestoreDestFileCheck(string chamId, string parameterName) { string newParameterName = parameterName; //有文件夹的处理方式 if (parameterName.Contains("\\")) { int index = 1; while (true) { int firstIndex = parameterName.IndexOf("\\"); string firstStr = parameterName.Substring(0, firstIndex); string tempRecipeDirectory = ""; string lastStr = parameterName.Substring(firstIndex + 1, parameterName.Length - firstStr.Length - 1); if (firstStr.Contains("(") && firstStr.Contains(")") && (firstStr.IndexOf("(") < firstStr.IndexOf(")")) && (firstStr.IndexOf(")") == firstStr.Length - 1)) { var tempFirstStr = firstStr.Remove(firstStr.IndexOf("("), firstStr.IndexOf(")")); newParameterName = $"{tempFirstStr}({index}){lastStr}"; tempRecipeDirectory = $"{tempFirstStr}({index})"; } else { newParameterName = $"{firstStr}({index})\\{lastStr}"; tempRecipeDirectory = $"{firstStr}({index})"; } var fileName = getParameterDirPath(chamId) + newParameterName + ".rcp"; DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(fileName)); if (CreateRestoreDirectory.ContainsKey(chamId) && CreateRestoreDirectory[chamId].Contains(tempRecipeDirectory)) { break; } else if (di.Exists) { index++; } else { if (!CreateRestoreDirectory.ContainsKey(chamId)) { List recipeDicectory = new List(); recipeDicectory.Add(tempRecipeDirectory); CreateRestoreDirectory.Add(chamId, recipeDicectory); } else { CreateRestoreDirectory[chamId].Add(tempRecipeDirectory); } di.Create(); break; } } } //直接文件的处理方式 else { int index = 1; while (true) { if (parameterName.Contains("(") && parameterName.Contains(")") && (parameterName.IndexOf("(") < parameterName.IndexOf(")")) && (parameterName.IndexOf(")") == parameterName.Length - 1)) { var tempFirstStr = parameterName.Remove(parameterName.IndexOf("("), parameterName.IndexOf(")")); newParameterName = $"{tempFirstStr}({index})"; } else { newParameterName = $"{parameterName}({index})"; break; } } } return getParameterDirPath(chamId) + newParameterName + ".rcp"; } public bool RestoreParameter(string chamId, bool isSaveLink, List parameterNames) { try { string filePath = getParameterBackupDirPath(chamId); CreateRestoreDirectory.Clear(); foreach (var item in parameterNames) { string strdest = chamId.Remove(5, 14); //string destFilePath = GenerateRecipeFilePath(strdest, item); string destFilePath = RestoreDestFileCheck(strdest, item); string sourceFilePath = GenerateBackupParameterFilePath(chamId, item); if (File.Exists(sourceFilePath)) { DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(destFilePath)); if (!di.Exists) di.Create(); File.Copy(sourceFilePath, destFilePath, true); } if (isSaveLink) { string recipeContent = LoadRestoreParameter(chamId, item, false); var xmlRecipe = new XmlDocument(); try { string chamberType = chamId.Split('\\')[0]; string processType = chamId.Split('\\')[1]; if (string.IsNullOrEmpty(recipeContent)) continue; xmlRecipe.LoadXml(recipeContent); XmlNodeList nodeSteps = xmlRecipe.SelectNodes($"Aitex/TableRecipeData/Module[@Name='{processType}']/Step"); XmlNode nodeConfig = xmlRecipe.SelectNodes($"Aitex/TableRecipeData/Config")[0]; switch (processType) { case "WaferFlow": string strSystemReicpeName = nodeConfig.Attributes["SystemRecipe"]?.Value; if (!string.IsNullOrEmpty(strSystemReicpeName)) { string subSourceFilePath = GenerateBackupParameterFilePath($"{chamId.Split('\\')[0]}\\System", strSystemReicpeName); string subDestFilePath = RestoreDestFileCheck($"{_chamberId}\\System", strSystemReicpeName); if (File.Exists(subSourceFilePath)) { DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(subDestFilePath)); if (!di.Exists) di.Create(); File.Copy(subSourceFilePath, subDestFilePath, true); } } foreach (var step in nodeSteps) { XmlElement nodestep = step as XmlElement; string strModuleName = nodestep.Attributes["ModuleName"]?.Value; if (string.IsNullOrEmpty(strModuleName)) { continue; } else { string[] temp = strModuleName.Split(',')[0].Split(' '); if (temp.Length > 1) strModuleName = temp[1]; } var linkRecipeName = nodestep.Attributes["RecipeName"].Value; if (string.IsNullOrEmpty(linkRecipeName)) { continue; } string[] subRecipeNames = linkRecipeName.Split(','); foreach (var subitem in subRecipeNames) { string subRecipeName = string.Empty; string[] subRecipeNameStrings = subitem.Split(':'); if (subRecipeNameStrings.Length > 1) { subRecipeName = subRecipeNameStrings[1]; } else { subRecipeName = subRecipeNameStrings[0]; } if (ovenModuleName.Contains(strModuleName)) { strModuleName = "Oven"; } string subSourceFilePath = GenerateBackupParameterFilePath($"{chamId.Split('\\')[0]}\\{strModuleName}", subRecipeName); string subDestFilePath = RestoreDestFileCheck($"{_chamberId}\\{strModuleName}", subRecipeName); if (File.Exists(subSourceFilePath)) { DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(subDestFilePath)); if (!di.Exists) di.Create(); File.Copy(subSourceFilePath, subDestFilePath, true); } if (strModuleName == "COT") { string subCotPath = GenerateBackupParameterFilePath($"{ _chamberId}\\{strModuleName}", subRecipeName); var subXmlRecipe = new XmlDocument(); string subRecipeContent = LoadParameter($"{ _chamberId}\\{strModuleName}", subRecipeName, false); if (string.IsNullOrEmpty(subRecipeContent)) continue; subXmlRecipe.LoadXml(subRecipeContent); XmlNode subNodeConfig = subXmlRecipe.SelectNodes($"Aitex/TableRecipeData/Config")[0]; string subPumpRecipeName = subNodeConfig.Attributes["COTPumpRecipe"]?.Value; if (!string.IsNullOrEmpty(subPumpRecipeName)) { string subPumpSourceFilePath = GenerateBackupParameterFilePath($"{chamId.Split('\\')[0]}\\Pump", subPumpRecipeName); string subPumpDestFilePath = RestoreDestFileCheck($"{_chamberId}\\Pump", subPumpRecipeName); if (File.Exists(subPumpSourceFilePath)) { DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(subPumpDestFilePath)); if (!di.Exists) di.Create(); File.Copy(subPumpSourceFilePath, subPumpDestFilePath, true); } } } } } break; case "COT": case "DEV": string pumpRecipeName = nodeConfig.Attributes["COTPumpRecipe"]?.Value; if (!string.IsNullOrEmpty(pumpRecipeName)) { string subSourceFilePath = GenerateBackupParameterFilePath($"{chamId.Split('\\')[0]}\\Pump", pumpRecipeName); string subDestFilePath = RestoreDestFileCheck($"{_chamberId}\\Pump", pumpRecipeName); if (File.Exists(subSourceFilePath)) { DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(subDestFilePath)); if (!di.Exists) di.Create(); File.Copy(subSourceFilePath, subDestFilePath, true); } } break; case "Dummy": foreach (var step in nodeSteps) { XmlElement nodestep = step as XmlElement; string regularSequence = nodestep.Attributes["RegularSequence"]?.Value; string preSequence = nodestep.Attributes["PreSequence"]?.Value; if (!string.IsNullOrEmpty(regularSequence)) { string[] regularSequences = regularSequence.Split(';'); foreach (var subItem in regularSequences) { if (string.IsNullOrEmpty(subItem)) continue; var pumpRecipe = GetKeyValue(subItem, "PumpRecipe"); if (!string.IsNullOrEmpty(pumpRecipe)) { string subSourceFilePath = GenerateBackupParameterFilePath($"{chamId.Split('\\')[0]}\\Pump", pumpRecipe); string subDestFilePath = RestoreDestFileCheck($"{_chamberId}\\Pump", pumpRecipe); if (File.Exists(subSourceFilePath)) { DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(subDestFilePath)); if (!di.Exists) di.Create(); File.Copy(subSourceFilePath, subDestFilePath, true); } } } } if (!string.IsNullOrEmpty(preSequence)) { string[] preSequences = preSequence.Split(';'); foreach (var subItem in preSequences) { if (string.IsNullOrEmpty(subItem)) continue; var pumpRecipe = GetKeyValue(item, "PumpRecipe"); if (!string.IsNullOrEmpty(pumpRecipe)) { string subSourceFilePath = GenerateBackupParameterFilePath($"{chamId.Split('\\')[0]}\\Pump", pumpRecipe); string subDestFilePath = RestoreDestFileCheck($"{_chamberId}\\Pump", pumpRecipe); if (File.Exists(subSourceFilePath)) { DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(subDestFilePath)); if (!di.Exists) di.Create(); File.Copy(subSourceFilePath, subDestFilePath, true); } } } } } break; case "Wash": foreach (var step in nodeSteps) { XmlElement nodestep = step as XmlElement; string sequence = nodestep.Attributes["Sequence"]?.Value; if (string.IsNullOrEmpty(sequence)) { continue; } var subSequences = sequence.Split(';'); foreach (var subSeq in subSequences) { if (string.IsNullOrEmpty(subSeq)) { continue; } var pumpRecipe = GetKeyValue(subSeq, "PumpRecipe"); if (!string.IsNullOrEmpty(pumpRecipe)) { string subSourceFilePath = GenerateBackupParameterFilePath($"{chamId.Split('\\')[0]}\\Pump", pumpRecipe); string subDestFilePath = RestoreDestFileCheck($"{_chamberId}\\Pump", pumpRecipe); if (File.Exists(subSourceFilePath)) { DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(subDestFilePath)); if (!di.Exists) di.Create(); File.Copy(subSourceFilePath, subDestFilePath, true); } } } } break; case "ADH": case "Oven": break; } } catch (Exception ex) { LOG.Write(ex); continue; } } } } catch (Exception ex) { LOG.Write(ex, "Backup Parameter file error"); } return true; } private void EventInfo(string message) { _rcpContext.PostInfoEvent(message); } private void EventWarning(string message) { _rcpContext.PostWarningEvent(message); } private void EventAlarm(string message) { _rcpContext.PostAlarmEvent(message); } private void InfoDialog(string message) { _rcpContext.PostInfoDialogMessage(message); } private void WarningDialog(string message) { _rcpContext.PostWarningDialogMessage(message); } //private void AlarmDialog(string message) //{ // _rcpContext.PostAlarmDialogMessage(message); //} private void EventDialog(string message, List reason) { string msg = message; foreach (var r in reason) { msg += "\r\n" + r; } _rcpContext.PostDialogEvent(msg); } /// /// get recipe's file path /// /// /// public string GenerateParameterFilePath(string chamId, string parameterName) { return getParameterDirPath(chamId) + parameterName + ".rcp"; } private string GenerateBackupParameterFilePath(string chamId, string parameterName) { return getParameterBackupDirPath(chamId) + parameterName + ".rcp"; } /// /// get recipe's dir path /// /// /// private string getParameterDirPath(string chamId) { var dir = string.Format("{0}{1}\\", PathManager.GetParameterDir(), chamId); DirectoryInfo di = new DirectoryInfo(dir); if (!di.Exists) di.Create(); return dir; } /// /// get parameter's dir path /// /// /// private string getParameterBackupDirPath(string chamId) { var dir = string.Format("{0}{1}\\", PathManager.GetParameterBackupDir(), chamId); DirectoryInfo di = new DirectoryInfo(dir); if (!di.Exists) di.Create(); return dir; } /// /// delete a recipe folder /// /// /// /// public bool DeleteFolder(string chamId, string folderName) { try { Directory.Delete(getParameterDirPath(chamId) + folderName, true); EventInfo(string.Format(Resources.RecipeFileManager_DeleteFolder_RecipeFolder0DeleteSucceeded, folderName)); } catch (Exception ex) { LOG.Write(ex, "删除recipe folder 出错"); EventAlarm(string.Format("recipe folder {0} delete failed", folderName)); return false; } return true; } /// /// save as recipe content /// /// /// /// /// public bool SaveAsParameter(string chamId, string recipeName, string recipeContent) { var path = GenerateParameterFilePath(chamId, recipeName); if (File.Exists(path)) { EventAlarm(string.Format(Resources.RecipeFileManager_SaveAsRecipe_RecipeFile0savefailed, recipeName)); return false; } return SaveParameter(chamId, recipeName, recipeContent, true, true); } /// /// save recipe content /// /// /// /// /// public bool SaveParameter(string chamId, string parameterName, string parameterContent, bool clearBarcode, bool notifyUI) { //validate recipe format when saving a recipe file //var reasons1 = new List(); //var reasons2 = new List(); //ValidateRecipe(chamId, recipeName, recipeContent, out reasons1); //CheckRecipe(chamId, recipeContent, out reasons2); //reasons1.AddRange(reasons2); //if (reasons1.Count > 0) //{ // EventDialog(string.Format( Resources.RecipeFileManager_SaveRecipe_SaveRecipeContentError, recipeName), reasons1); //} bool ret = true; try { var path = GenerateParameterFilePath(chamId, parameterName); FileInfo fi = new FileInfo(path); if (!fi.Directory.Exists) fi.Directory.Create(); XmlDocument xml = new XmlDocument(); xml.LoadXml(parameterContent); XmlTextWriter writer = new XmlTextWriter(path, Encoding.UTF8); writer.Formatting = Formatting.Indented; xml.Save(writer); writer.Close(); if (notifyUI) { InfoDialog(string.Format(Resources.RecipeFileManager_SaveRecipe_RecipeFile0SaveCompleted, parameterName)); } else { EV.PostMessage("System", EventEnum.GeneralInfo, string.Format(Resources.RecipeFileManager_SaveRecipe_RecipeFile0SaveCompleted, parameterName)); } } catch (Exception ex) { LOG.Write(ex, "保存recipe file 出错"); if (notifyUI) { WarningDialog(string.Format(Resources.RecipeFileManager_SaveRecipe_RecipeFile0SaveFailed, parameterName)); } ret = false; } return ret; } /// /// save recipe content /// /// /// /// /// public bool SaveRestoreParameter(string chamId, string parameterName, string parameterContent, bool clearBarcode, bool notifyUI) { //validate recipe format when saving a recipe file //var reasons1 = new List(); //var reasons2 = new List(); //ValidateRecipe(chamId, recipeName, recipeContent, out reasons1); //CheckRecipe(chamId, recipeContent, out reasons2); //reasons1.AddRange(reasons2); //if (reasons1.Count > 0) //{ // EventDialog(string.Format( Resources.RecipeFileManager_SaveRecipe_SaveRecipeContentError, recipeName), reasons1); //} bool ret = true; try { var path = GenerateBackupParameterFilePath(chamId, parameterName); FileInfo fi = new FileInfo(path); if (!fi.Directory.Exists) fi.Directory.Create(); XmlDocument xml = new XmlDocument(); xml.LoadXml(parameterContent); XmlTextWriter writer = new XmlTextWriter(path, Encoding.UTF8); writer.Formatting = Formatting.Indented; xml.Save(writer); writer.Close(); if (notifyUI) { InfoDialog(string.Format(Resources.RecipeFileManager_SaveRecipe_RecipeFile0SaveCompleted, parameterName)); } else { EV.PostMessage("System", EventEnum.GeneralInfo, string.Format(Resources.RecipeFileManager_SaveRecipe_RecipeFile0SaveCompleted, parameterName)); } } catch (Exception ex) { LOG.Write(ex, "保存recipe file 出错"); if (notifyUI) { WarningDialog(string.Format(Resources.RecipeFileManager_SaveRecipe_RecipeFile0SaveFailed, parameterName)); } ret = false; } return ret; } /// /// create a new recipe folder /// /// /// /// public bool CreateFolder(string chamId, string folderName) { try { Directory.CreateDirectory(getParameterDirPath(chamId) + folderName); EventInfo(string.Format(Resources.RecipeFileManager_CreateFolder_RecipeFolder0Created, folderName)); } catch (Exception ex) { LOG.Write(ex, "create recipe folder failed"); EventAlarm(string.Format(Resources.RecipeFileManager_CreateFolder_RecipeFolder0CreateFailed, folderName)); return false; } return true; } /// /// Rename recipe folder name /// /// /// /// /// public bool RenameFolder(string chamId, string oldName, string newName) { try { string oldPath = getParameterDirPath(chamId) + oldName; string newPath = getParameterDirPath(chamId) + newName; Directory.Move(oldPath, newPath); EventInfo(string.Format(Resources.RecipeFileManager_RenameFolder_RecipeFolder0renamed, oldName, newName)); } catch (Exception ex) { LOG.Write(ex, "Rename recipe folder failed"); EventAlarm(string.Format(Resources.RecipeFileManager_RenameFolder_RecipeFolder0RenameFailed, oldName, newName)); return false; } return true; } public XmlDocument ParameterDom = new XmlDocument(); private string GetParameterBody(string chamberId, string nodePath) { if (_rcpContext == null) return string.Empty; string schema = _rcpContext.GetParameterDefiniton(chamberId); ParameterDom = new XmlDocument(); ParameterDom.LoadXml(schema); XmlNode node = ParameterDom.SelectSingleNode(nodePath); return node.OuterXml; } public string ChamberType { get; set; } public string Version { get; set; } public int TableNumber { get; set; } public Dictionary> GetGroupParameterTemplate() { try { XmlNode nodeRoot = ParameterDom.SelectSingleNode("Aitex/TableParameterFormat"); ChamberType = nodeRoot.Attributes["ChamberType"].Value; Version = nodeRoot.Attributes["Version"].Value; TableNumber = nodeRoot.Attributes["TableNumber"] != null ? Convert.ToInt32(nodeRoot.Attributes["TableNumber"].Value) : 0; } catch (Exception ex) { LOG.Write(ex); return null; } var columns = new Dictionary>(); ParameterTemplateColumnBase col = null; XmlNodeList nodes = ParameterDom.SelectNodes("Aitex/TableParameterFormat/Catalog/Group"); foreach (XmlNode node in nodes) { XmlNodeList childNodes = node.SelectNodes("Step"); int tableNum = 1; string nameList = null; if (node.Attributes["TableNumber"] != null) { tableNum = Convert.ToInt32(node.Attributes["TableNumber"].Value); } if (node.Attributes["NameList"] != null) { nameList = node.Attributes["NameList"].Value.Replace("\t\t\t\t ", "").Replace("\n", "").Replace("\r", ""); } if (nameList != null && nameList.Contains(",")) { tableNum = tableNum > nameList.Split(',').Length ? tableNum : nameList.Split(',').Length; } string[] namelist = new string[tableNum]; for (int i = 0; i < namelist.Length; i++) { namelist[i] = ""; } if (!string.IsNullOrEmpty(nameList)) { var list = nameList.Split(','); for (int i = 0; i < list.Length; i++) { namelist[i] = list[i]; } } for (int i = 1; i <= tableNum; i++) { var sigcolumns = new ObservableCollection(); foreach (XmlNode step in childNodes) { //step number if (step.Attributes["ControlName"].Value == "TableNo") { col = new ParameterTemplateColumnBase() { DisplayName = "Table", ControlName = "TableNo", }; sigcolumns.Add(col); continue; } switch (step.Attributes["InputType"].Value) { case "TextInput": col = new ParameterTemplateColumnBase() { ValueType = "TextInput", ModuleName = step.Attributes["ModuleName"].Value, ControlName = step.Attributes["ControlName"].Value, DisplayName = step.Attributes["DisplayName"].Value, IsEnable = !bool.Parse(step.Attributes["ReadOnly"] != null ? step.Attributes["ReadOnly"].Value : "false"), EnableConfig = step.Attributes["EnableConfig"] != null && Convert.ToBoolean(step.Attributes["EnableConfig"].Value), Default = step.Attributes["DefaultValue"] != null ? step.Attributes["DefaultValue"].Value : "", EnableTolerance = step.Attributes["EnableTolerance"] != null && Convert.ToBoolean(step.Attributes["EnableTolerance"].Value), }; sigcolumns.Add(col); break; case "NumInput": col = new ParameterTemplateColumnBase() { ValueType = "NumInput", ModuleName = step.Attributes["ModuleName"].Value, ControlName = step.Attributes["ControlName"].Value, DisplayName = step.Attributes["DisplayName"].Value, InputMode = step.Attributes["InputMode"].Value, Minimun = double.Parse(step.Attributes["Min"].Value), Maximun = double.Parse(step.Attributes["Max"].Value), Value = step.Attributes["DefaultValue"] != null ? Convert.ToInt32(step.Attributes["DefaultValue"].Value) : 0, IsEnable = !bool.Parse(step.Attributes["ReadOnly"] != null ? step.Attributes["ReadOnly"].Value : "false"), EnableConfig = step.Attributes["EnableConfig"] != null && Convert.ToBoolean(step.Attributes["EnableConfig"].Value), EnableTolerance = step.Attributes["EnableTolerance"] != null && Convert.ToBoolean(step.Attributes["EnableTolerance"].Value), }; sigcolumns.Add(col); break; case "DoubleInput": col = new ParameterTemplateColumnBase() { ValueType = "DoubleInput", ModuleName = step.Attributes["ModuleName"].Value, ControlName = step.Attributes["ControlName"].Value, DisplayName = step.Attributes["DisplayName"].Value, InputMode = step.Attributes["InputMode"].Value, Minimun = double.Parse(step.Attributes["Min"].Value), Maximun = double.Parse(step.Attributes["Max"].Value), Value = step.Attributes["DefaultValue"] != null ? Convert.ToDouble(step.Attributes["DefaultValue"].Value) : 0.0f, IsEnable = !bool.Parse(step.Attributes["ReadOnly"] != null ? step.Attributes["ReadOnly"].Value : "false"), EnableConfig = step.Attributes["EnableConfig"] != null && Convert.ToBoolean(step.Attributes["EnableConfig"].Value), EnableTolerance = step.Attributes["EnableTolerance"] != null && Convert.ToBoolean(step.Attributes["EnableTolerance"].Value), }; sigcolumns.Add(col); break; case "EditableSelection": col = new ParameterTemplateColumnBase() { ValueType = "EditableSelection", ModuleName = step.Attributes["ModuleName"].Value, Default = step.Attributes["Default"] != null ? step.Attributes["Default"].Value : "", ControlName = step.Attributes["ControlName"].Value, DisplayName = step.Attributes["DisplayName"].Value, IsEnable = !bool.Parse(step.Attributes["ReadOnly"] != null ? step.Attributes["ReadOnly"].Value : "false"), EnableConfig = step.Attributes["EnableConfig"] != null && Convert.ToBoolean(step.Attributes["EnableConfig"].Value), EnableTolerance = step.Attributes["EnableTolerance"] != null && Convert.ToBoolean(step.Attributes["EnableTolerance"].Value), }; XmlNodeList items = step.SelectNodes("Item"); foreach (XmlNode item in items) { Option opt = new Option(); opt.ControlName = item.Attributes["ControlName"].Value; opt.DisplayName = item.Attributes["DisplayName"].Value; ((ParameterTemplateColumnBase)col).Options.Add(opt); } sigcolumns.Add(col); break; case "ReadOnlySelection": case "LoopSelection": col = new ParameterTemplateColumnBase() { ValueType = "LoopSelection", IsReadOnly = bool.Parse(step.Attributes["ReadOnly"] != null ? step.Attributes["ReadOnly"].Value : "false"), ModuleName = step.Attributes["ModuleName"].Value, ControlName = step.Attributes["ControlName"].Value, DisplayName = step.Attributes["DisplayName"].Value, EnableConfig = step.Attributes["EnableConfig"] != null && Convert.ToBoolean(step.Attributes["EnableConfig"].Value), EnableTolerance = step.Attributes["EnableTolerance"] != null && Convert.ToBoolean(step.Attributes["EnableTolerance"].Value), }; XmlNodeList options = step.SelectNodes("Item"); foreach (XmlNode item in options) { Option opt = new Option(); opt.ControlName = item.Attributes["ControlName"].Value; opt.DisplayName = item.Attributes["DisplayName"].Value; ((ParameterTemplateColumnBase)col).Options.Add(opt); } sigcolumns.Add(col); break; case "PopSetting": col = new ParameterTemplateColumnBase() { ValueType = "LoopSelection", ModuleName = step.Attributes["ModuleName"].Value, ControlName = step.Attributes["ControlName"].Value, DisplayName = step.Attributes["DisplayName"].Value, EnableConfig = step.Attributes["EnableConfig"] != null && Convert.ToBoolean(step.Attributes["EnableConfig"].Value), EnableTolerance = step.Attributes["EnableTolerance"] != null && Convert.ToBoolean(step.Attributes["EnableTolerance"].Value), }; sigcolumns.Add(col); break; } } if (tableNum == 1 && string.IsNullOrEmpty(nameList)) { columns.Add(node.Attributes["DisplayName"].Value, sigcolumns); } else if (tableNum == 1 && !string.IsNullOrEmpty(nameList)) { columns.Add($"{node.Attributes["DisplayName"].Value}\t1\t{namelist[0]}", sigcolumns); } else { columns.Add($"{node.Attributes["DisplayName"].Value}\t{i}\t{namelist[i - 1]}", sigcolumns); } } } return columns; } /// /// get reactor's recipe format define file /// /// /// public string GetParameterFormatXml(string chamberId) { var rtn = GetParameterBody(chamberId, "/Aitex/TableParameterFormat"); return rtn; } /// /// get reactor's template recipe file /// /// /// public string GetParameterTemplate(string chamberId) { if (_rcpContext != null) return _rcpContext.GetParameterTemplate(chamberId); return GetParameterBody(chamberId, "/Aitex/TableParameterData"); } /// /// get reactor's template recipe file /// /// /// public string GetParameterSchema(string chamberId) { if (_rcpContext == null) return string.Empty; string schema = _rcpContext.GetParameterDefiniton(chamberId); XmlDocument dom = new XmlDocument(); dom.LoadXml(schema); XmlNode node = dom.SelectSingleNode("/Aitex/TableParameterSchema"); return node.InnerXml; } public string GetParameterByBarcode(string chamberId, string barcode) { try { string parameterPath = PathManager.GetRecipeDir() + chamberId + "\\"; var di = new DirectoryInfo(parameterPath); var fis = di.GetFiles("*.rcp", SearchOption.AllDirectories); XmlDocument xml = new XmlDocument(); foreach (var fi in fis) { string str = fi.FullName.Substring(parameterPath.Length); if (!str.Contains("HistoryParameter\\")) { xml.Load(fi.FullName); if (xml.SelectSingleNode(string.Format("/TableParameterData[@Barcode='{0}']", barcode)) != null) { return str.Substring(0, str.LastIndexOf('.')); } } } return string.Empty; } catch (Exception ex) { LOG.Write(ex); return string.Empty; } } public List GetFileNodeParameterListByPath(string chamberId) { List files = new List(); var baseFolderPath = getParameterDirPath(chamberId); DirectoryInfo curFolderInfo = new DirectoryInfo(baseFolderPath); FileNodeItem nodeItem = new FileNodeItem(); nodeItem.IsFile = false; GenerateFileNodeParameterList(chamberId, curFolderInfo, nodeItem); files.Add(nodeItem); return files; } FileNodeItem GenerateFileNodeParameterList(string chamberId, DirectoryInfo currentDir, FileNodeItem nodeItem) { int trimLength = getParameterDirPath(chamberId).Length; DirectoryInfo[] dirInfos = currentDir.GetDirectories(); foreach (DirectoryInfo dirInfo in dirInfos) { GenerateFileNodeParameterList(chamberId, dirInfo, nodeItem); } FileInfo[] fileInfos = currentDir.GetFiles("*.rcp"); foreach (FileInfo fileInfo in fileInfos) { string fileStr = fileInfo.FullName.Substring(trimLength).TrimStart(new char[] { '\\' }); ; FileNodeItem subNodeItem = new FileNodeItem(); subNodeItem.Name = fileInfo.Name.Replace(".rcp", ""); subNodeItem.FullPath = subNodeItem.Name; subNodeItem.PrefixPath = chamberId; subNodeItem.IsFile = true; ReadFileSetFileNode(chamberId, subNodeItem.Name, subNodeItem); nodeItem.Files.Add(subNodeItem); } return nodeItem; } private void ReadFileSetFileNode(string chamberId,string fileName, FileNodeItem fileNodeItem) { string content = LoadParameter(chamberId, fileName, false); XmlDocument _doc = new XmlDocument(); _doc.LoadXml(content); XmlElement nodeData = _doc.SelectSingleNode($"Aitex/TableParameterData") as XmlElement; fileNodeItem.Creator = nodeData.GetAttribute("CreatedBy"); fileNodeItem.Description = nodeData.GetAttribute("Description"); fileNodeItem.CreatTime = nodeData.GetAttribute("CreationTime"); fileNodeItem.ReviseTime = nodeData.GetAttribute("LastRevisionTime"); fileNodeItem.Revisor = nodeData.GetAttribute("LastRevisedBy"); fileNodeItem.Permission = nodeData.GetAttribute("Permission"); fileNodeItem.Level = nodeData.GetAttribute("Level"); fileNodeItem.IsChecked = nodeData.GetAttribute("CheckResult") == "Correct"; } } }