/// <summary> /// Method called when the add-in is run. /// </summary> public void Execute(IDesignContext context) { // This example code places some new objects from the Standard Library into the active model of the project. if (context.ActiveModel != null) { // Example of how to place some new fixed objects into the active model. // This example code places three new fixed objects: a Source, a Server, and a Sink. IIntelligentObjects intelligentObjects = context.ActiveModel.Facility.IntelligentObjects; IFixedObject sourceObject = intelligentObjects.CreateObject("Source", new FacilityLocation(-10, 0, -10)) as IFixedObject; IFixedObject serverObject = intelligentObjects.CreateObject("Server", new FacilityLocation(0, 0, 0)) as IFixedObject; IFixedObject sinkObject = intelligentObjects.CreateObject("Sink", new FacilityLocation(10, 0, 10)) as IFixedObject; // Example of how to place some new link objects into the active model (to add network paths between nodes). // This example code places two new link objects: a Path connecting the Source 'output' node to the Server 'input' node, // and a Path connecting the Server 'output' node to the Sink 'input' node. INodeObject sourceOutputNode = sourceObject.Nodes[0]; INodeObject serverInputNode = serverObject.Nodes[0]; INodeObject serverOutputNode = serverObject.Nodes[1]; INodeObject sinkInputNode = sinkObject.Nodes[0]; ILinkObject pathObject1 = intelligentObjects.CreateLink("Path", sourceOutputNode, serverInputNode, null) as ILinkObject; ILinkObject pathObject2 = intelligentObjects.CreateLink("Path", serverOutputNode, sinkInputNode, null) as ILinkObject; // Example of how to edit the property of an object. // This example code edits the 'ProcessingTime' property of the added Server object. serverObject.Properties["ProcessingTime"].Value = "100"; } }
private static Uri ResolveDocumentationUri(ILinkObject link, string rel) { var template = new UriTemplate(link.Href.ToString()); template.SetParameter("rel", rel); return new Uri(template.Resolve()); }
private static Uri ResolveDocumentationUri(ILinkObject link, string rel) { var template = new UriTemplate(link.Href.ToString()); template.SetParameter("rel", rel); return(new Uri(template.Resolve())); }
public static ILinkObject ParseLinkObject(ILinkObject link, Dictionary <string, string> parameters) { if (parameters.Count > 0) { var resolvedLink = link.ResolveTemplated((UriTemplate x) => { foreach (var keyValue in parameters) { x.AddParameter(keyValue.Key, keyValue.Value); } return(x.Resolve()); }); return(resolvedLink); } else { return(link); } }
/// <summary> /// Method called when the add-in is run. /// </summary> public void Execute(IDesignContext context) { var warnings = new List <String>(); // This example code places some new objects from the Standard Library into the active model of the project. if (context.ActiveModel != null) { IIntelligentObjects intelligentObjects = context.ActiveModel.Facility.IntelligentObjects; IFixedObject bed = intelligentObjects.CreateObject("Bed", new FacilityLocation(0, 0, 0)) as IFixedObject; IFixedObject sourceObject = intelligentObjects.CreateObject("Source", new FacilityLocation(-10, 0, -10)) as IFixedObject; IFixedObject serverObject = intelligentObjects.CreateObject("Server", new FacilityLocation(0, 0, 0)) as IFixedObject; IFixedObject sinkObject = intelligentObjects.CreateObject("Sink", new FacilityLocation(10, 0, 10)) as IFixedObject; IEntityInstanceReferencePropertyDefinition modelentitiy = intelligentObjects.CreateObject("Patient", new FacilityLocation(-20, 0, -10)) as IEntityInstanceReferencePropertyDefinition; ITransporterInstanceReferencePropertyDefinition regnurse = intelligentObjects.CreateObject("Worker", new FacilityLocation(-30, 0, -30)) as ITransporterInstanceReferencePropertyDefinition; //var RNurseName = context.ActiveModel.Facility.IntelligentObjects["Worker1"]; //RNurseName.Properties["Name"].Value = "RegularNurse"; //var modelentitiy = context.ActiveModel.Facility.IntelligentObjects["Patient"]; // Example of how to place some new link objects into the active model (to add network paths between nodes). // This example code places two new link objects: a Path connecting the Source 'output' node to the Server 'input' node, // and a Path connecting the Server 'output' node to the Sink 'input' node. INodeObject sourceOutputNode = sourceObject.Nodes[0]; INodeObject serverInputNode = serverObject.Nodes[0]; INodeObject serverOutputNode = serverObject.Nodes[1]; INodeObject sinkInputNode = sinkObject.Nodes[0]; INodeObject bedinputnode = bed.Nodes[0]; INodeObject bedoutputnode = bed.Nodes[1]; ILinkObject pathObject1 = intelligentObjects.CreateLink("Path", sourceOutputNode, serverInputNode, null) as ILinkObject; ILinkObject pathObject2 = intelligentObjects.CreateLink("Path", serverOutputNode, bedinputnode, null) as ILinkObject; ILinkObject pathObject3 = intelligentObjects.CreateLink("Path", bedoutputnode, sinkInputNode, null) as ILinkObject; // Example of how to edit the property of an object. // This example code edits the 'ProcessingTime' property of the added Server object. serverObject.Properties["ProcessingTime"].Value = "0"; sourceObject.Properties["EntityType"].Value = "Patient1"; var defaultEntity = context.ActiveModel.Facility.IntelligentObjects["Patient1"]; defaultEntity.Properties["RegNurseCheckTime"].Value = "HospitalData.RNRounding"; defaultEntity.Properties["TherapistCheckTime"].Value = "HospitalData.TherapistRounding"; defaultEntity.Properties["AssistantNurseCheckTime"].Value = "HospitalData.ANRounding"; defaultEntity.Properties["BedStayTime"].Value = "HospitalData.BedStayTime"; defaultEntity.Properties["TherapistVisitTime"].Value = "HospitalData.TherapistVisitTime"; defaultEntity.Properties["RegNurseVisitTime"].Value = "HospitalData.RegNurseVisitTime"; defaultEntity.Properties["AssistantNurseNextVisit"].Value = "HospitalData.AssistantNurseNextVisit"; ITable entitydatatable = context.ActiveModel.Tables.Create("HospitalData"); var i = entitydatatable.Columns.AddEntityReferenceColumn("PatientTypes"); var mix = entitydatatable.Columns.AddRealColumn("Mix", 0.0); var admisiontime = entitydatatable.Columns.AddExpressionColumn("AdmissionTime", "0.0"); (admisiontime as IUnitizedTableColumn).UnitType = SimioUnitType.Time; var rnrounding = entitydatatable.Columns.AddExpressionColumn("RNRounding", "0.0"); var nurserounding = entitydatatable.Columns.AddExpressionColumn("ANRounding", "0.0"); var therapistrounding = entitydatatable.Columns.AddExpressionColumn("TherapistRounding", "0.0"); var bedtime = entitydatatable.Columns.AddExpressionColumn("BedStayTime", "0.0"); var RVisitTime = entitydatatable.Columns.AddExpressionColumn("RegNurseVisitTime", "0.0"); var TVisitTime = entitydatatable.Columns.AddExpressionColumn("TherapistVisitTime", "0.0"); var AVisitTime = entitydatatable.Columns.AddExpressionColumn("AssistantNurseNextVisit", "0.0"); //Add Resource Type List var resourceType = context.ActiveModel.NamedLists["ResourceType"]; if (resourceType != null) { warnings.Add(string.Format(FormatListMessage(resourceType.Name))); } else { resourceType = context.ActiveModel.NamedLists.AddObjectList("ResourceType"); var firstRow = resourceType.Rows.Create(); firstRow.Properties[0].Value = "Source"; var secondRow = resourceType.Rows.Create(); secondRow.Properties[0].Value = "Server"; var thirdRow = resourceType.Rows.Create(); thirdRow.Properties[0].Value = "Patient"; var fourthRow = resourceType.Rows.Create(); fourthRow.Properties[0].Value = "RegNurse"; var fifthRow = resourceType.Rows.Create(); fifthRow.Properties[0].Value = "Therapist"; var sixthrow = resourceType.Rows.Create(); sixthrow.Properties[0].Value = "Ass.Nurse"; var seventhRow = resourceType.Rows.Create(); seventhRow.Properties[0].Value = "Sink"; var eigthRow = resourceType.Rows.Create(); eigthRow.Properties[0].Value = "Bed"; var ninthRow = resourceType.Rows.Create(); ninthRow.Properties[0].Value = "Worker"; } //Adding Resource Table ITable resourceTable = context.ActiveModel.Tables["Resources"]; if (resourceTable != null) { warnings.Add(string.Format(FormatListMessage(resourceTable.Name))); } else { resourceTable = context.ActiveModel.Tables.Create("Resources"); var j = resourceTable.Columns.AddObjectReferenceColumn("ResourceName"); j.FilterToResources = false; j.IsKey = true; var resourceTypes = resourceTable.Columns.AddListReferenceColumn("ResourceType"); resourceTypes.ListName = ("ResourceType"); resourceTypes.DefaultString = ("Bed"); } ITable link = context.ActiveModel.Tables["LinkBetweenResources"]; if (link != null) { warnings.Add(string.Format(FormatLinkMessage(link.Name))); } else { } //var modelentity1 = context.ActiveModel.Facility.IntelligentObjects["Patient"]; //modelentity1.Properties["BedStayTime"].Value = "5"; } #endregion }
public Uri GetUri(ILinkObject linkObject) { return(new Uri(Address + linkObject.Href)); }
public void analizar() { if (listaAeropuertos.Count > 0 && listaVuelos.Count > 0) { // ISimioProject _simioproject; string _projectPathAndFile = getPathActual(); //MessageBox.Show(_projectPathAndFile); string[] warnings; currentProject = SimioProjectFactory.LoadProject("Model.spfx", out warnings); //ISimioProject project = SimioProjectFactory.LoadProject("Test.spfx", out warnings); IModel model = currentProject.Models["Model"]; IExperiment experiment = model.Experiments.Create("Experiment"); // Setup the experiment (optional) // Specify run times. //string experiment_ScenarioEnded = "2"; double runtime = 2; IRunSetup setup = experiment.RunSetup; setup.StartingTime = new DateTime(2010, 10, 01); setup.WarmupPeriod = TimeSpan.FromHours(0); setup.EndingTime = experiment.RunSetup.StartingTime + TimeSpan.FromDays(runtime); experiment.ConfidenceLevel = ExperimentConfidenceLevelType.Point90; experiment.LowerPercentile = 5; experiment.UpperPercentile = 95; //model.Facility.IntelligentObjects["aeropuerto"].Properties["InitialCapacity"].Value = "69"; int contador = 0; Random rnd = new Random(); IFixedObject source = model.Facility.IntelligentObjects["fuente"] as IFixedObject; source.Properties["InterarrivalTime"].Value = "Random.Poisson(60/300)"; foreach (var air in listaAeropuertos) { TiempoServicioGeneral = rnd.Next(1, 3); IFixedObject aeropuerto = model.Facility.IntelligentObjects.CreateObject("Server", new FacilityLocation(air.x, air.y, air.z)) as IFixedObject; aeropuerto.ObjectName = air.nombre; switch (TiempoServicioGeneral) { case 1: aeropuerto.Properties["ProcessingTime"].Value = "Random.Triangular(35,45,60)"; break; case 2: aeropuerto.Properties["ProcessingTime"].Value = "Random.Triangular(30,40,50)"; break; case 3: aeropuerto.Properties["ProcessingTime"].Value = "Random.Uniform(30,50)"; break; } aeropuerto.Properties["FailureType"].Value = air.tipoFalla; aeropuerto.Properties["OffShiftRule"].Value = "FinishWorkAlreadyStarted"; aeropuerto.Properties["CountBetweenFailures"].Value = air.cantEntreFallas.ToString(); aeropuerto.Properties["TimeToRepair"].Value = air.tiempoReparacion.ToString(); IFixedObject mezclador = model.Facility.IntelligentObjects.CreateObject("Combiner", new FacilityLocation(air.x, air.y + 30, air.z)) as IFixedObject; String n = air.nombre + "C"; mezclador.ObjectName = n; IFixedObject sourceAviones = model.Facility.IntelligentObjects.CreateObject("Source", new FacilityLocation(air.x, air.y + 30, air.z)) as IFixedObject; n = air.nombre + "S"; sourceAviones.ObjectName = n; sourceAviones.Properties["InitialCapacity"].Value = "100"; IIntelligentObject pista = model.Facility.IntelligentObjects.CreateObject("Server", new FacilityLocation(air.x, air.y + 30, air.z)); n = air.nombre + "P"; pista.ObjectName = n; pista.Properties["InitialCapacity"].Value = air.capacidadPista.ToString(); ILinkObject path1 = model.Facility.IntelligentObjects.CreateLink("TimePath", source.Nodes[0], aeropuerto.Nodes[0], null) as ILinkObject; path1.Properties["TravelTime"].Value = air.tiempoAbordajeDespegue.ToString(); ILinkObject path = model.Facility.IntelligentObjects.CreateLink("Path", sourceAviones.Nodes[0], mezclador.Nodes[0], null) as ILinkObject; ILinkObject path3 = model.Facility.IntelligentObjects.CreateLink("Path", aeropuerto.Nodes[0], mezclador.Nodes[1], null) as ILinkObject; //nuevo.Properties[""].Value = air.tiempoPersonas; //nuevo.Properties[""].Value = air.tiempoAbordajeDespegue; //nuevo.Properties[""].Value = air.id; //if (contador == 0) //{ // model.Facility.IntelligentObjects["DefaultEntity"].Properties["Name"].Value = air.nombre; //} //else //{ // model.Facility.IntelligentObjects["Server"+(contador+1)].Properties["Name"].Value = air.nombre; //} //model.Facility.IntelligentObjects[2].Properties["name"].Value = air.nombre; contador = contador + 1; } //model.Facility.IntelligentObjects.CreateObject("Server", new FacilityLocation(0, 0, 0)); /* * // Add event handler for events from experiment * experiment.ScenarioEnded += new EventHandler<ScenarioEndedEventArgs>(experiment_ScenarioEnded); * experiment.RunCompleted += new EventHandler<RunCompletedEventArgs>(experiment_RunCompleted); * experiment.RunProgressChanged += new EventHandler<RunProgressChangedEventArgs>(experiment_RunProgressChanged); * experiment.ReplicationEnded += new EventHandler<ReplicationEndedEventArgs>(experiment_ReplicationEnded); */ // Run Experiment, will call event handler methods when finished etc. SimioProjectFactory.SaveProject(currentProject, "Nuevo.spfx", out warnings); } else { MessageBox.Show("Debe cargar ambos archivos."); } }
/// <summary> /// Method called when the add-in is run. /// </summary> public void Execute(IDesignContext context) { //Open Status Window string marker = "Begin."; try { // Check to make sure a model has been opened in Simio if (context.ActiveModel == null) { MessageBox.Show("You must have an active model to run this add-in.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } // Open the file. Return immediately if the user cancels the file open dialog var getFile = new OpenFileDialog(); getFile.Filter = "Excel Files(*.xlsx)|*.xlsx"; if (getFile.ShowDialog() == DialogResult.Cancel) { MessageBox.Show("Canceled by user.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } StatusWindow = new StatusWindow($"Importing From Excel Spreadsheet {getFile.FileName}"); StatusWindow.Show(); Boolean importVertices = true; // Update Status Window StatusWindow.UpdateProgress(25, "Checking worksheets"); ExcelPackage package = new ExcelPackage(new System.IO.FileInfo(getFile.FileName)); ExcelWorkbook xlWorkbook = package.Workbook; // Create the node and link sheet lists List <ExcelWorksheet> objectsWorksheets = new List <ExcelWorksheet>(); List <ExcelWorksheet> linksWorksheets = new List <ExcelWorksheet>(); List <ExcelWorksheet> verticesWorksheets = new List <ExcelWorksheet>(); marker = "Categorizing Worksheets."; // Look through every sheet and categorize them according to objects, links, or vertices // We'll do objects first, then vertices, then links foreach (ExcelWorksheet ws in package.Workbook.Worksheets) { string wsName = ws.Name.ToLower(); if (wsName.Length >= 5) { // Add any sheet that name starts with 'objects' to the objects list if (wsName.ToLower().StartsWith("objects")) { objectsWorksheets.Add(ws); } // Add any sheet that name starts with 'links' to the link list else if (wsName.ToLower().StartsWith("links")) { linksWorksheets.Add(ws); } // Add any sheet that name starts with 'vertices' to the link list else if (wsName.ToLower().StartsWith("vertices")) { verticesWorksheets.Add(ws); } } } // foreach worksheet if (objectsWorksheets.Count + linksWorksheets.Count == 0) { logit("Workbook contains no valid object or link worksheets."); return; } // Update Status Window StatusWindow.UpdateProgress(50, "Building Objects"); // get a reference to intelligent objects... var intellObjects = context.ActiveModel.Facility.IntelligentObjects; // ... and a reference to Elements var elements = context.ActiveModel.Elements; // use bulk update to import quicker context.ActiveModel.BulkUpdate(model => { // Read and create the objects. int addedCount; int updatedCount; foreach (ExcelWorksheet ows in objectsWorksheets) { var dim = ows.Dimension; if (dim.Rows == 0) { continue; } marker = $"Reading {dim.Rows} rows from Object sheet {ows.Name}"; logit(marker); addedCount = 0; updatedCount = 0; for (int ri = 2; ri <= dim.Rows; ri++) { marker = $"Sheet={ows.Name} Row={ri}"; string className = ows.Cells[ri, 1].Value?.ToString(); string itemName = ows.Cells[ri, 2].Value?.ToString(); if (string.IsNullOrEmpty(className) || string.IsNullOrEmpty(itemName)) { logit($"{marker}: Empty ClassName or ItemName"); continue; } // Find the coordinates for the object double x = 0.0, y = 0.0, z = 0.0; bool updateCoordinates = true; if (!GetCellAsDouble(ows.Cells[ri, 3], ref x) || !GetCellAsDouble(ows.Cells[ri, 4], ref y) || !GetCellAsDouble(ows.Cells[ri, 5], ref z)) { updateCoordinates = false; } // Add the coordinates to the intelligent object FacilityLocation loc = new FacilityLocation(x, y, z); var intellObj = intellObjects[itemName]; if (intellObj == null) { intellObj = intellObjects.CreateObject(className, loc); if (intellObj == null) { logit($"{marker}: Cannot create object with className={className}"); continue; } intellObj.ObjectName = itemName; addedCount++; } else { // update coords of existing one. if (updateCoordinates) { intellObj.Location = loc; } updatedCount++; } // Set Size double length = intellObj.Size.Length; double width = intellObj.Size.Width; double height = intellObj.Size.Height; if (GetCellAsDouble(ows.Cells[ri, 6], ref length)) { if (length == 0) { length = intellObj.Size.Length; } } if (GetCellAsDouble(ows.Cells[ri, 7], ref width)) { if (width == 0) { width = intellObj.Size.Width; } } if (GetCellAsDouble(ows.Cells[ri, 8], ref height)) { if (height == 0) { height = intellObj.Size.Height; } } FacilitySize fs = new FacilitySize(length, width, height); intellObj.Size = fs; // update properties on object, which are columns 9 onward for (int ci = 9; ci <= dim.Columns; ci++) { // By convention, the first row on the sheet is the header row, which contains the Property name. string propertyName = ows.Cells[1, ci]?.Value as string; if (string.IsNullOrEmpty(propertyName)) { continue; } propertyName = propertyName.ToLower(); // Find a property with matching text (case insensitive) IProperty prop = intellObj.Properties.AsQueryable() .SingleOrDefault(rr => rr.Name.ToString().ToLower() == propertyName); if (prop == null) { continue; } string cellValue = ows.Cells[ri, ci].Value?.ToString(); if (cellValue != null) { if (!SetPropertyValue(prop, cellValue, out string explanation)) { logit(explanation); } } } // for each column property } // foreach row logit($"Added {addedCount} objects and updated {updatedCount} objects"); } // for each object worksheet var vertexList = new ArrayList(); // Update Status Window if (importVertices) { // Add additional vertices foreach (ExcelWorksheet vws in verticesWorksheets) { var dim = vws.Dimension; if (dim.Rows > 0) { logit($"Info: Reading {dim.Rows} rows from sheet {vws.Name}"); } addedCount = 0; updatedCount = 0; for (int ri = 2; ri <= dim.Rows; ri++) { marker = $"Sheet={vws.Name} Row={ri}"; var cell = vws.Cells[ri, 1]; string linkName = cell.Value as string; if (string.IsNullOrEmpty(linkName)) { logit($"{marker}: No LinkName"); goto DoneWithVertexRows; } // Find the coordinates for the vertex double x = double.MinValue, y = double.MinValue, z = double.MinValue; if (!GetCellAsDouble(vws.Cells[ri, 2], ref x) || !GetCellAsDouble(vws.Cells[ri, 3], ref y) || !GetCellAsDouble(vws.Cells[ri, 4], ref z)) { logit($"{marker}: Bad Vertex Coordinate"); goto DoneWithVertexRows; } vertexList.Add(new string[] { linkName, x.ToString(), y.ToString(), z.ToString() }); } // for each row of vertices DoneWithVertexRows:; } // for each vertex worksheet } // Check if we are importing vertices StatusWindow.UpdateProgress(75, "Building Links"); // Get Links Data // Read and create the links. foreach (ExcelWorksheet lws in linksWorksheets) { var dim = lws.Dimension; if (dim.Rows > 0) { marker = $"Info: Reading {dim.Rows} rows from sheet {lws.Name}"; logit(marker); } addedCount = 0; updatedCount = 0; for (int ri = 2; ri <= dim.Rows; ri++) { marker = $"Sheet={lws.Name} Row={ri}"; string className = lws.Cells[ri, 1]?.Value as string; if (string.IsNullOrEmpty(className)) { logit($"{marker}: Invalid ClassName={className}"); goto DoneWithLinkRow; } string linkName = lws.Cells[ri, 2]?.Value as string; if (string.IsNullOrEmpty(linkName)) { logit($"{marker}: Invalid LinkName={linkName}"); goto DoneWithLinkRow; } string fromNodeName = lws.Cells[ri, 3]?.Value as string; if (string.IsNullOrEmpty(fromNodeName)) { logit($"{marker}: Invalid FromNodeName={fromNodeName}"); goto DoneWithLinkRow; } string toNodeName = lws.Cells[ri, 4]?.Value as string; if (string.IsNullOrEmpty(toNodeName)) { logit($"{marker}: Invalid ToNodeName={toNodeName}"); goto DoneWithLinkRow; } var fromNode = intellObjects[fromNodeName] as INodeObject; if (fromNode == null) { logit($"{marker} Cannot find 'from' node name {fromNodeName}"); goto DoneWithWorksheets; } var toNode = intellObjects[toNodeName] as INodeObject; if (toNode == null) { logit($"{marker}: Cannot find 'to' node name {toNodeName}"); goto DoneWithWorksheets; } // if link exists, remove and re-add var link = intellObjects[linkName]; if (link != null) { intellObjects.Remove(link); updatedCount++; } else { addedCount++; } // Define List of Facility Locations List <FacilityLocation> locs = new List <FacilityLocation>(); foreach (string[] loc in vertexList) { if (loc[0] == linkName) { double xx = double.MinValue, yy = double.MinValue, zz = double.MinValue; xx = Convert.ToDouble(loc[1]); yy = Convert.ToDouble(loc[2]); zz = Convert.ToDouble(loc[3]); // If coordinates are good, add vertex to facility locations if (xx > double.MinValue & yy > double.MinValue & zz > double.MinValue) { // Add the coordinates to the intelligent object FacilityLocation loc2 = new FacilityLocation(xx, yy, zz); locs.Add(loc2); } } } // for each vertex // Add Link link = intellObjects.CreateLink(className, fromNode, toNode, locs); if (link == null) { logit($"{marker}: Cannot create Link"); goto DoneWithWorksheets; } link.ObjectName = linkName; // Add Link to Network string networkName = lws.Cells[ri, 5]?.Value as string; if (string.IsNullOrEmpty(networkName)) { logit($"{marker}: Null NetworkName"); goto DoneWithLinkRow; } var netElement = elements[networkName]; if (netElement == null) { netElement = elements.CreateElement("Network"); netElement.ObjectName = networkName; } var netElementObj = netElement as INetworkElementObject; if (netElement != null) { ILinkObject linkOb = (ILinkObject)link; linkOb.Networks.Add(netElementObj); } // get header row on sheet // update properties on object, which begin with column index 6 for (int ci = 6; ci <= dim.Columns; ci++) { string propertyName = lws.Cells[1, ci]?.Value as string; // Find a property with matching text (case insensitive) IProperty prop = link.Properties.AsQueryable() .SingleOrDefault(rr => rr.Name.ToString().ToLower() == propertyName.ToLower()); if (prop != null) { string cellValue = lws.Cells[ri, ci]?.Value as string; if (!SetPropertyValue(prop, cellValue, out string explanation)) { logit(explanation); goto DoneWithLinkRow; } } } // foreach column DoneWithLinkRow:; } // for each row marker = $"Info: Added {addedCount} links and deleted and re-added {updatedCount} existing links"; logit(marker); DoneWithWorksheets:; } }); // Update Status Window StatusWindow.UpdateProgress(100, "Complete"); } catch (Exception ex) { throw new ApplicationException($"Marker={marker} Err={ex.Message}"); } finally { StatusWindow.UpdateLogs(Loggerton.Instance); } }