publicstatic UtilityNetwork GetUtilityNetworkFromTable(Tabletable){UtilityNetworkutilityNetwork=null;if(table.IsControllerDatasetSupported()){// Tables can belong to multiple controller datasets, but at most one of them will be a UtilityNetworkIReadOnlyList<Dataset>controllerDatasets= table.GetControllerDatasets();foreach(Dataset controllerDataset in controllerDatasets){if(controllerDataset is UtilityNetwork){utilityNetwork= controllerDataset as UtilityNetwork;}else{
controllerDataset.Dispose();}}}returnutilityNetwork;}
Get a Utility Network from a Layer
// This routine obtains a utility network from a FeatureLayer, SubtypeGroupLayer, or UtilityNetworkLayerpublicstatic UtilityNetwork GetUtilityNetworkFromLayer(Layerlayer){UtilityNetworkutilityNetwork=null;if(layer is UtilityNetworkLayer){UtilityNetworkLayerutilityNetworkLayer= layer as UtilityNetworkLayer;utilityNetwork= utilityNetworkLayer.GetUtilityNetwork();}elseif(layer is SubtypeGroupLayer){CompositeLayercompositeLayer= layer as CompositeLayer;utilityNetwork= GetUtilityNetworkFromLayer(compositeLayer.Layers.First());}elseif(layer is FeatureLayer){FeatureLayerfeatureLayer= layer as FeatureLayer;using(FeatureClassfeatureClass= featureLayer.GetFeatureClass()){if(featureClass.IsControllerDatasetSupported()){IReadOnlyList<Dataset>controllerDatasets=newList<Dataset>();controllerDatasets= featureClass.GetControllerDatasets();foreach(Dataset controllerDataset in controllerDatasets){if(controllerDataset is UtilityNetwork){utilityNetwork= controllerDataset as UtilityNetwork;}else{
controllerDataset.Dispose();}}}}}returnutilityNetwork;}
Elements
Fetching a Row from an Element
// usage : using (var row = FetchRowFromElement(...))publicstatic Row FetchRowFromElement(UtilityNetworkutilityNetwork,Elementelement){// Get the table from the elementusing(Tabletable= utilityNetwork.GetTable(element.NetworkSource)){// Create a query filter to fetch the appropriate rowQueryFilterqueryFilter=new QueryFilter(){ObjectIDs=newList<long>(){ element.ObjectID }};// Fetch and return the rowusing(RowCursorrowCursor= table.Search(queryFilter)){if(rowCursor.MoveNext()){return rowCursor.Current;}returnnull;}}}
Editing Associations
Create a utility network association
// Create edit operationEditOperationeditOperation=new EditOperation();
editOperation.Name ="Create structural attachment association";// Create a RowHandle for the poleElementpoleElement= utilityNetwork.CreateElement(poleAssetType, poleGlobalID);RowHandlepoleRowHandle=new RowHandle(poleElement, utilityNetwork);// Create a RowHandle for the transformer bankElementtransformerBankElement= utilityNetwork.CreateElement(transformerBankAssetType, transformerBankGlobalID);RowHandletransformerBankRowHandle=new RowHandle(transformerBankElement, utilityNetwork);// Attach the transformer bank to the poleAssociationDescriptionstructuralAttachmentAssociationDescription=new AssociationDescription(AssociationType.Attachment, poleRowHandle, transformerBankRowHandle);
editOperation.Create(structuralAttachmentAssociationDescription);
editOperation.Execute();
Create utility network features and associations in a single edit operation
// Create an EditOperationEditOperationeditOperation=new EditOperation();
editOperation.Name ="Create pole; create transformer bank; attach transformer bank to pole";// Create the transformer bankRowTokentransformerBankToken= editOperation.CreateEx(transformerBankLayer, transformerBankAttributes);// Create a poleRowTokenpoleToken= editOperation.CreateEx(poleLayer, poleAttributes);// Create a structural attachment association between the pole and the transformer bankRowHandlepoleHandle=new RowHandle(poleToken);RowHandletransformerBankHandle=new RowHandle(transformerBankToken);AssociationDescriptionpoleAttachment=new AssociationDescription(AssociationType.Attachment, poleHandle, transformerBankHandle);
editOperation.Create(poleAttachment);// Execute the EditOperation
editOperation.Execute();
Subnetworks and Tiers
Find a Tier given a Domain Network name and Tier name
Life cycle for a simple radial subnetwork with one controller
// Create a subnetwork named "Radial1" with a single controller// elementR1 represents the device that serves as the subnetwork controller (e.g., circuit breaker)SubnetworksubnetworkRadial1= subnetworkManager.EnableControllerInEditOperation(mediumVoltageTier, elementR1,"Radial1","R1","my description","my notes");// ...// Update the subnetwork and refresh the map
subnetworkRadial1.Update();
MapView.Active.Redraw(true);// ...// At some point, a subnetwork will need to be deleted.// First step is to disable the controller
subnetworkManager.DisableControllerInEditOperation(elementR1);// At this point, the subnetwork is deleted, but all of the rows that have been labeled with the subnetwork ID need to be updated
subnetworkRadial1.Update();
MapView.Active.Redraw(true);// The final step is to notify external systems (if any) using the Export Subnetwork geoprocessing tool
Life cycle for a mesh subnetwork with multiple controllers
// Create a subnetwork named "Mesh1" from three controllers// elementM1, elementM2, and elementM3 represent the devices that serve as subnetwork controllers (e.g., network protectors)
subnetworkManager.EnableController(lowVoltageMeshTier, elementM1,"Mesh1","M1","my description","my notes");
subnetworkManager.EnableController(lowVoltageMeshTier, elementM2,"Mesh1","M2","my description","my notes");SubnetworksubnetworkMesh1= subnetworkManager.EnableController(lowVoltageMeshTier, elementM3,"Mesh1","M3","my description","my notes");
subnetworkMesh1.Update();
MapView.Active.Redraw(true);// ...// When deleting the subnetwork, each controller must be disabled before the subnetwork itself is deleted
subnetworkManager.DisableControllerInEditOperation(elementM1);
subnetworkManager.DisableControllerInEditOperation(elementM2);
subnetworkManager.DisableControllerInEditOperation(elementM3);// After the subnetwork is deleted, all of the rows that have been labeled with the subnetwork ID need to be updated
subnetworkMesh1.Update();
MapView.Active.Redraw(true);// The final step is to notify external systems (if any) using the Export Subnetwork geoprocessing tool
Life cycle for a multifeed radial subnetwork with two controllers
// Create a subnetwork named "R2, R3" from two controllers// elementR2 and elementR3 represent the devices that serve as subnetwork controllers (e.g., circuit breakers)
subnetworkManager.EnableControllerInEditOperation(mediumVoltageTier, elementR2,"R2, R3","R2","my description","my notes");
subnetworkManager.EnableControllerInEditOperation(mediumVoltageTier, elementR3,"R2, R3","R3","my description","my notes");// If the tie switch between them is opened, the original subnetwork controllers must be disabled and re-enabled with different names// This will create two new subnetworks, named "R2" and "R3"
subnetworkManager.DisableControllerInEditOperation(elementR2);
subnetworkManager.DisableControllerInEditOperation(elementR3);SubnetworksubnetworkR2= subnetworkManager.EnableControllerInEditOperation(mediumVoltageTier, elementR2,"R2","R2","my description","my notes");SubnetworksubnetworkR3= subnetworkManager.EnableControllerInEditOperation(mediumVoltageTier, elementR3,"R3","R3","my description","my notes");
subnetworkR2.Update();
subnetworkR3.Update();
MapView.Active.Redraw(true);
IReadOnlyList<Element>startingPointList=newList<Element>();// Code to fill in list of starting points goes here...TraceArgumenttraceArgument=new TraceArgument(startingPointList);TraceConfigurationtraceConfiguration=new TraceConfiguration();// Code to fill in trace configuration goes here...
traceArgument.Configuration =traceConfiguration;
Create a Condition to compare a Network Attribute against a set of values
// Create a NetworkAttribute object for the Lifecycle network attribute from the UtilityNetworkDefinitionusing(NetworkAttributelifecycleNetworkAttribute= utilityNetworkDefinition.GetNetworkAttribute("Lifecycle")){// Create a NetworkAttributeComparison that stops traversal if Lifecycle <> "In Design" (represented by the constant InDesign)NetworkAttributeComparisoninDesignNetworkAttributeComparison=new NetworkAttributeComparison(lifecycleNetworkAttribute, Operator.NotEqual, InDesign);// Create a NetworkAttributeComparison to stop traversal if Lifecycle <> "In Service" (represented by the constant InService)NetworkAttributeComparisoninServiceNetworkAttributeComparison=new NetworkAttributeComparison(lifecycleNetworkAttribute, Operator.NotEqual, InService);// Combine these two comparisons together with "And"AndlifecycleFilter=new And(inDesignNetworkAttributeComparison, inServiceNetworkAttributeComparison);// Final condition stops traversal if Lifecycle <> "In Design" and Lifecycle <> "In Service"
traceConfiguration.Traversability.Barriers =lifecycleFilter;}
Create a Function
// Get a NetworkAttribute object for the Load network attribute from the UtilityNetworkDefinitionusing(NetworkAttributeloadNetworkAttribute= utilityNetworkDefinition.GetNetworkAttribute("Load")){// Create a function to sum the LoadAddsumLoadFunction=new Add(loadNetworkAttribute);// Add this function to our trace configuration
traceConfiguration.Functions =newList<Function>(){ sumLoadFunction };}
Create a FunctionBarrier
// Create a NetworkAttribute object for the Shape length network attribute from the UtilityNetworkDefinitionusing(NetworkAttributeshapeLengthNetworkAttribute= utilityNetworkDefinition.GetNetworkAttribute("Shape length")){// Create a function that adds up shape lengthAddlengthFunction=new Add(shapeLengthNetworkAttribute);// Create a function barrier that stops traversal after 1000 feetFunctionBarrierdistanceBarrier=new FunctionBarrier(lengthFunction, Operator.GreaterThan,1000.0);// Set this function barrier
traceConfiguration.Traversability.FunctionBarriers =newList<FunctionBarrier>(){ distanceBarrier };}
Create an output condition
// Create an output category to filter the trace results to only include// features with the "Service Point" category assigned
traceConfiguration.OutputCondition =new CategoryComparison(CategoryOperator.IsEqual,"Service Point");
Create a Propagator
// Get a NetworkAttribute object for the Phases Normal attribute from the UtilityNetworkDefinitionusing(NetworkAttributenormalPhaseAttribute= utilityNetworkDefinition.GetNetworkAttribute("Phases Normal")){// Create a propagator to propagate the Phases Normal attribute downstream from the source, using a Bitwise And function// Allow traversal to continue as long as the Phases Normal value includes any of the ABC phases// (represented by the constant ABCPhase)PropagatorphasePropagator=new Propagator(normalPhaseAttribute, PropagatorFunction.BitwiseAnd, Operator.IncludesAny, ABCPhase);// Assign this propagator to our trace configuration
traceConfiguration.Propagators =newList<Propagator>(){ phasePropagator };}
Using Function Results
// Get the FunctionOutputResult from the trace resultsFunctionOutputResultfunctionOutputResult= traceResults.OfType<FunctionOutputResult>().First();// First() can be used here if only one Function was included in the TraceConfiguration.Functions collection.// Otherwise you will have to search the list for the correct FunctionOutput object.FunctionOutputfunctionOutput= functionOutputResult.FunctionOutputs.First();// Extract the total load from the GlobalValue propertydoubletotalLoad=(double)functionOutput.Value;
Network Diagrams
Get a list of inconsistent Network Diagrams
publicList<NetworkDiagram>GetInconsistentDiagrams(UtilityNetworkutilityNetwork){// Get the DiagramManager from the utility networkusing(DiagramManagerdiagramManager= utilityNetwork.GetDiagramManager()){List<NetworkDiagram>myList=newList<NetworkDiagram>();// Loop through the network diagrams in the diagram managerforeach(NetworkDiagram diagram in diagramManager.GetNetworkDiagrams()){NetworkDiagramInfodiagramInfo= diagram.GetDiagramInfo();// If the diagram is not a system diagram and is in an inconsistent state, add it to our listif(!diagramInfo.IsSystem && diagram.GetConsistencyState()!= NetworkDiagramConsistencyState.DiagramIsConsistent){
myList.Add(diagram);}else{
diagram.Dispose();// If we are not returning it we need to Dispose it}}returnmyList;}}
Retrieve Diagram Elements
publicvoidRetrieveDiagramElements(MapViewmapView,NetworkDiagramnetworkDiagram){// Create a DiagramElementQueryByExtent to retrieve diagram element junctions whose extent// intersects the active map extentDiagramElementQueryByExtentelementQuery=new DiagramElementQueryByExtent();
elementQuery.ExtentOfInterest = MapView.Active.Extent;
elementQuery.AddContents =false;
elementQuery.QueryDiagramJunctionElement =true;
elementQuery.QueryDiagramEdgeElement =false;
elementQuery.QueryDiagramContainerElement =false;// Use this DiagramElementQueryByExtent as an argument to the QueryDiagramElements methodDiagramElementQueryResultresult= networkDiagram.QueryDiagramElements(elementQuery);}
Change the Layout of a Network Diagram
publicvoidDiagramElementQueryResultAndNetworkDiagramSubsetClasses(Geodatabasegeodatabase,DiagramManagerdiagramManager,stringdiagramName){// Retrieve a diagramusing(NetworkDiagramdiagramTest= diagramManager.GetNetworkDiagram(diagramName)){// Create a DiagramElementQueryByElementTypes query object to get the diagram elements we want to work withDiagramElementQueryByElementTypesquery=new DiagramElementQueryByElementTypes();
query.QueryDiagramJunctionElement =true;
query.QueryDiagramEdgeElement =true;
query.QueryDiagramContainerElement =true;// Retrieve those diagram elementsDiagramElementQueryResultelements= diagramTest.QueryDiagramElements(query);// Create a NetworkDiagramSubset object to edit this set of diagram elementsNetworkDiagramSubsetsubset=new NetworkDiagramSubset();
subset.DiagramJunctionElements = elements.DiagramJunctionElements;
subset.DiagramEdgeElements = elements.DiagramEdgeElements;
subset.DiagramContainerElements = elements.DiagramContainerElements;// Edit the shapes of the diagram elements - left as an exercise for the student
TranslateDiagramElements(subset);// Save the new layout of the diagram elements
diagramTest.SaveLayout(subset,true);}}
Open a diagram window from a Network Diagram
// Create a diagram layer from a NetworkDiagram (myDiagram)DiagramLayerdiagramLayer=await QueuedTask.Run<DiagramLayer>(()=>{// Create the diagram mapvarnewMap= MapFactory.Instance.CreateMap(myDiagram.Name, ArcGIS.Core.CIM.MapType.NetworkDiagram, MapViewingMode.Map);if(newMap==null)returnnull;// Open the diagram mapvarmapPane= ArcGIS.Desktop.Core.ProApp.Panes.CreateMapPaneAsync(newMap, MapViewingMode.Map);if(mapPane==null)returnnull;//Add the diagram to the mapreturn newMap.AddDiagramLayer(myDiagram);});