frmMain.vb
' Copyright 2012 ESRI ' ' All rights reserved under the copyright laws of the United States ' and applicable international laws, treaties, and conventions. ' ' You may freely redistribute and use this sample code, with or ' without modification, provided you include the original copyright ' notice and use restrictions. ' ' See the use restrictions. ' Imports Microsoft.VisualBasic Imports System Imports System.Drawing Imports System.Collections Imports System.ComponentModel Imports System.Windows.Forms Imports System.Data Imports ESRI.ArcGIS.Carto Imports ESRI.ArcGIS.Controls Imports ESRI.ArcGIS.esriSystem Imports ESRI.ArcGIS.SystemUI Imports ESRI.ArcGIS.NetworkAnalyst Imports ESRI.ArcGIS.Geodatabase ' This is the main form of the application. Namespace NAEngine ''' <summary> ''' Summary description for Form1. ''' </summary> Public Class frmMain : Inherits System.Windows.Forms.Form ''' <summary> ''' Required designer variable. ''' </summary> Private components As System.ComponentModel.Container = Nothing Private splitter1 As System.Windows.Forms.Splitter ' Context menu objects for NAWindow's context menu Private contextMenu1 As System.Windows.Forms.ContextMenu Private WithEvents miLoadLocations As System.Windows.Forms.MenuItem Private WithEvents miClearLocations As System.Windows.Forms.MenuItem Private WithEvents miAddItem As System.Windows.Forms.MenuItem ' ArcGIS Controls on the form Private axMapControl1 As ESRI.ArcGIS.Controls.AxMapControl Private axLicenseControl1 As ESRI.ArcGIS.Controls.AxLicenseControl Private axToolbarControl1 As ESRI.ArcGIS.Controls.AxToolbarControl Private WithEvents axTOCControl1 As ESRI.ArcGIS.Controls.AxTOCControl ' Listen for context menu on NAWindow Private m_onContextMenu As IEngineNAWindowEventsEx_OnContextMenuEventHandler Private m_OnNetworkLayersChanged As IEngineNetworkAnalystEnvironmentEvents_OnNetworkLayersChangedEventHandler Private m_OnCurrentNetworkLayerChanged As IEngineNetworkAnalystEnvironmentEvents_OnCurrentNetworkLayerChangedEventHandler ' Reference to ArcGIS Network Analyst extension Environment Private m_naEnv As IEngineNetworkAnalystEnvironment ' Reference to NAWindow. Need to hold on to reference for events to work. Private m_naWindow As IEngineNAWindow ' Menu for our commands on the TOC context menu Private m_menuLayer As IToolbarMenu ' incrementor for auto generated names Private Shared autogenInt As Integer = 0 Public Sub New() ' ' Required for Windows Form Designer support ' InitializeComponent() End Sub ''' <summary> ''' Clean up any resources being used. ''' </summary> Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean) ESRI.ArcGIS.ADF.COMSupport.AOUninitialize.Shutdown() If disposing Then If Not components Is Nothing Then components.Dispose() End If End If MyBase.Dispose(disposing) End Sub #Region "Windows Form Designer generated code" ''' <summary> ''' Required method for Designer support - do not modify ''' the contents of this method with the code editor. ''' </summary> Private Sub InitializeComponent() Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(frmMain)) Me.axMapControl1 = New ESRI.ArcGIS.Controls.AxMapControl() Me.axLicenseControl1 = New ESRI.ArcGIS.Controls.AxLicenseControl() Me.axToolbarControl1 = New ESRI.ArcGIS.Controls.AxToolbarControl() Me.splitter1 = New System.Windows.Forms.Splitter() Me.axTOCControl1 = New ESRI.ArcGIS.Controls.AxTOCControl() Me.contextMenu1 = New System.Windows.Forms.ContextMenu() Me.miLoadLocations = New System.Windows.Forms.MenuItem() Me.miClearLocations = New System.Windows.Forms.MenuItem() Me.miAddItem = New System.Windows.Forms.MenuItem() CType(Me.axMapControl1, System.ComponentModel.ISupportInitialize).BeginInit() CType(Me.axLicenseControl1, System.ComponentModel.ISupportInitialize).BeginInit() CType(Me.axToolbarControl1, System.ComponentModel.ISupportInitialize).BeginInit() CType(Me.axTOCControl1, System.ComponentModel.ISupportInitialize).BeginInit() Me.SuspendLayout() ' ' axMapControl1 ' Me.axMapControl1.Dock = System.Windows.Forms.DockStyle.Fill Me.axMapControl1.Location = New System.Drawing.Point(227, 28) Me.axMapControl1.Name = "axMapControl1" Me.axMapControl1.OcxState = (CType(resources.GetObject("axMapControl1.OcxState"), System.Windows.Forms.AxHost.State)) Me.axMapControl1.Size = New System.Drawing.Size(645, 472) Me.axMapControl1.TabIndex = 2 ' ' axLicenseControl1 ' Me.axLicenseControl1.Enabled = True Me.axLicenseControl1.Location = New System.Drawing.Point(664, 0) Me.axLicenseControl1.Name = "axLicenseControl1" Me.axLicenseControl1.OcxState = (CType(resources.GetObject("axLicenseControl1.OcxState"), System.Windows.Forms.AxHost.State)) Me.axLicenseControl1.Size = New System.Drawing.Size(32, 32) Me.axLicenseControl1.TabIndex = 1 ' ' axToolbarControl1 ' Me.axToolbarControl1.Dock = System.Windows.Forms.DockStyle.Top Me.axToolbarControl1.Location = New System.Drawing.Point(0, 0) Me.axToolbarControl1.Name = "axToolbarControl1" Me.axToolbarControl1.OcxState = (CType(resources.GetObject("axToolbarControl1.OcxState"), System.Windows.Forms.AxHost.State)) Me.axToolbarControl1.Size = New System.Drawing.Size(872, 28) Me.axToolbarControl1.TabIndex = 0 ' ' splitter1 ' Me.splitter1.Location = New System.Drawing.Point(224, 28) Me.splitter1.Name = "splitter1" Me.splitter1.Size = New System.Drawing.Size(3, 472) Me.splitter1.TabIndex = 4 Me.splitter1.TabStop = False ' ' axTOCControl1 ' Me.axTOCControl1.Dock = System.Windows.Forms.DockStyle.Left Me.axTOCControl1.Location = New System.Drawing.Point(0, 28) Me.axTOCControl1.Name = "axTOCControl1" Me.axTOCControl1.OcxState = (CType(resources.GetObject("axTOCControl1.OcxState"), System.Windows.Forms.AxHost.State)) Me.axTOCControl1.Size = New System.Drawing.Size(224, 472) Me.axTOCControl1.TabIndex = 1 ' Me.axTOCControl1.OnMouseDown += New ESRI.ArcGIS.Controls.ITOCControlEvents_Ax_OnMouseDownEventHandler(Me.axTOCControl1_OnMouseDown); ' ' contextMenu1 ' Me.contextMenu1.MenuItems.AddRange(New System.Windows.Forms.MenuItem() {Me.miLoadLocations, Me.miClearLocations}) ' ' miLoadLocations ' Me.miLoadLocations.Index = 0 Me.miLoadLocations.Text = "Load Locations..." ' Me.miLoadLocations.Click += New System.EventHandler(Me.miLoadLocations_Click); ' ' miClearLocations ' Me.miClearLocations.Index = 1 Me.miClearLocations.Text = "Clear Locations" ' Me.miClearLocations.Click += New System.EventHandler(Me.miClearLocations_Click); ' ' miAddItem ' Me.miAddItem.Index = -1 Me.miAddItem.Text = "Add Item" ' Me.miAddItem.Click += New System.EventHandler(Me.miAddItem_Click); ' ' frmMain ' Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13) Me.ClientSize = New System.Drawing.Size(872, 500) Me.Controls.Add(Me.axLicenseControl1) Me.Controls.Add(Me.axMapControl1) Me.Controls.Add(Me.splitter1) Me.Controls.Add(Me.axTOCControl1) Me.Controls.Add(Me.axToolbarControl1) Me.Name = "frmMain" Me.Text = "Network Analyst Engine Application" ' Me.Load += New System.EventHandler(Me.frmMain_Load); CType(Me.axMapControl1, System.ComponentModel.ISupportInitialize).EndInit() CType(Me.axLicenseControl1, System.ComponentModel.ISupportInitialize).EndInit() CType(Me.axToolbarControl1, System.ComponentModel.ISupportInitialize).EndInit() CType(Me.axTOCControl1, System.ComponentModel.ISupportInitialize).EndInit() Me.ResumeLayout(False) End Sub #End Region ''' <summary> ''' The main entry point for the application. ''' </summary> <STAThread()> _ Shared Sub Main() Dim succeeded As Boolean = ESRI.ArcGIS.RuntimeManager.Bind(ESRI.ArcGIS.ProductCode.EngineOrDesktop) If succeeded Then Dim activeRunTimeInfo As ESRI.ArcGIS.RuntimeInfo = ESRI.ArcGIS.RuntimeManager.ActiveRuntime System.Diagnostics.Debug.Print(activeRunTimeInfo.Product.ToString()) Application.Run(New frmMain()) Else System.Windows.Forms.MessageBox.Show("Failed to bind to an active ArcGIS runtime") End If End Sub Private Sub frmMain_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load ' Add commands to the NALayer context menu m_menuLayer = New ToolbarMenuClass() Dim nItem As Integer = -1 m_menuLayer.AddItem(New cmdLoadLocations(), -1, ++nItem, False, esriCommandStyles.esriCommandStyleTextOnly) m_menuLayer.AddItem(New cmdRemoveLayer(), -1, ++nItem, False, esriCommandStyles.esriCommandStyleTextOnly) m_menuLayer.AddItem(New cmdClearAnalysisLayer(), -1, ++nItem, True, esriCommandStyles.esriCommandStyleTextOnly) m_menuLayer.AddItem(New cmdNALayerProperties(), -1, ++nItem, True, esriCommandStyles.esriCommandStyleTextOnly) ' Since this ToolbarMenu is a standalone popup menu use the SetHook method to ' specify the object that will be sent as a "hook" to the menu commands in their OnCreate methods. m_menuLayer.SetHook(axMapControl1) ' Add command for ArcGIS Network Analyst extension env properties to end of "Network Analyst" dropdown menu nItem = -1 Dim i As Integer = 0 Do While i < axToolbarControl1.Count Dim item As IToolbarItem = axToolbarControl1.GetItem(i) Dim mnu As IToolbarMenu = item.Menu If mnu Is Nothing Then i += 1 Continue Do End If Dim mnudef As IMenuDef = mnu.GetMenuDef() Dim name As String = mnudef.Name ' Find the ArcGIS Network Analyst extension solver menu drop down and note the index If name = "ControlToolsNetworkAnalyst_SolverMenu" Then nItem = i Exit Do End If i += 1 Loop If nItem >= 0 Then ' Using the index found above, get the solver menu drop down and add the Properties command to the end of it. Dim item As IToolbarItem = axToolbarControl1.GetItem(nItem) Dim mnu As IToolbarMenu = item.Menu If Not mnu Is Nothing Then mnu.AddItem(New cmdNAProperties(), -1, mnu.Count, True, esriCommandStyles.esriCommandStyleTextOnly) End If ' Since this ToolbarMenu is an item on the ToolbarControl the Hook is shared and initialized by the ToolbarControl. ' Therefore, SetHook is not called here, like it is for the menu above. End If ' Initialize naEnv variables m_naEnv = CommonFunctions.GetTheEngineNetworkAnalystEnvironment() If m_naEnv Is Nothing Then MessageBox.Show("Error: EngineNetworkAnalystEnvironment is not properly configured") Return End If m_naEnv.ZoomToResultAfterSolve = False m_naEnv.ShowAnalysisMessagesAfterSolve = CInt(esriEngineNAMessageType.esriEngineNAMessageTypeInformative Or esriEngineNAMessageType.esriEngineNAMessageTypeWarning) ' Set up the buddy control and initialize the NA extension, so we can get to NAWindow to listen to window events. ' This is necessary, as the various controls are not yet set up. They need to be in order to get the NAWindow's events. axToolbarControl1.SetBuddyControl(axMapControl1) Dim ext As IExtension = TryCast(m_naEnv, IExtension) Dim obj As Object = axToolbarControl1.Object ext.Startup(obj) ' m_naWindow is set after Startup of the Network Analyst extension m_naWindow = m_naEnv.NAWindow If m_naWindow Is Nothing Then MessageBox.Show("Error: Unexpected null NAWindow") Return End If m_onContextMenu = New IEngineNAWindowEventsEx_OnContextMenuEventHandler(AddressOf OnContextMenu) AddHandler CType(m_naWindow, IEngineNAWindowEventsEx_Event).OnContextMenu, m_onContextMenu m_OnNetworkLayersChanged = New IEngineNetworkAnalystEnvironmentEvents_OnNetworkLayersChangedEventHandler(AddressOf OnNetworkLayersChanged) AddHandler CType(m_naEnv, IEngineNetworkAnalystEnvironmentEvents_Event).OnNetworkLayersChanged, m_OnNetworkLayersChanged m_OnCurrentNetworkLayerChanged = New IEngineNetworkAnalystEnvironmentEvents_OnCurrentNetworkLayerChangedEventHandler(AddressOf OnCurrentNetworkLayerChanged) AddHandler CType(m_naEnv, IEngineNetworkAnalystEnvironmentEvents_Event).OnCurrentNetworkLayerChanged, m_OnCurrentNetworkLayerChanged End Sub ' Show the TOC context menu when an NALayer is right-clicked on Private Sub axTOCControl1_OnMouseDown(ByVal sender As Object, ByVal e As ESRI.ArcGIS.Controls.ITOCControlEvents_OnMouseDownEvent) Handles axTOCControl1.OnMouseDown If e.button <> 2 Then Return End If Dim item As esriTOCControlItem = esriTOCControlItem.esriTOCControlItemNone Dim map As IBasicMap = Nothing Dim layer As ILayer = Nothing Dim other As Object = Nothing Dim index As Object = Nothing 'Determine what kind of item has been clicked on axTOCControl1.HitTest(e.x, e.y, item, map, layer, other, index) ' Only implemented a context menu for NALayers. Exit if the layer is anything else. If (TryCast(layer, INALayer)) Is Nothing Then Return End If axTOCControl1.SelectItem(layer) ' Set the layer into the CustomProperty. ' This is used by the other commands to know what layer was right-clicked on ' in the table of contents. axMapControl1.CustomProperty = layer 'Popup the correct context menu and update the TOC when it's done. If item = esriTOCControlItem.esriTOCControlItemLayer Then m_menuLayer.PopupMenu(e.x, e.y, axTOCControl1.hWnd) Dim toc As ITOCControl = TryCast(axTOCControl1.Object, ITOCControl) toc.Update() End If End Sub Public Sub OnNetworkLayersChanged() ' The OnNetworkLayersChanged event is fired when a new INetworkLayer object is ' added, removed, or renamed within a map. ' If the INetworkLayer is renamed interactively through the user interface ' OnNetworkLayersChanged is fired. If the INetworkLayer is renamed programmatically ' using the ILayer::Name property OnNetworkLayersChanged is not fired. End Sub Public Sub OnCurrentNetworkLayerChanged() ' The OnCurrentNetworkLayerChanged event is fired when the user interactively ' changes the NetworkDataset or the IEngineNetworkAnalystEnvironment::CurrentNetworkLayer ' is set programatically. End Sub Public Function OnContextMenu(ByVal x As Integer, ByVal y As Integer) As Boolean Dim pt As System.Drawing.Point = Me.PointToClient(System.Windows.Forms.Cursor.Position) ' Get the active category Dim activeCategory As IEngineNAWindowCategory2 = TryCast(m_naWindow.ActiveCategory, IEngineNAWindowCategory2) If activeCategory Is Nothing Then Return False End If Dim separator As MenuItem = New MenuItem("-") miLoadLocations.Enabled = False miClearLocations.Enabled = False ' in order for the AddItem choice to appear in the context menu, the class ' should be an input class, and it should not be editable Dim pNAClassDefinition As INAClassDefinition = activeCategory.NAClass.ClassDefinition If pNAClassDefinition.IsInput Then miLoadLocations.Enabled = True miClearLocations.Enabled = True ' canEditShape should be false for AddItem to Apply (default is false) ' if it's a StandaloneTable canEditShape is implicitly false (there's no shape to edit) Dim canEditShape As Boolean = False Dim pFields As IFields = pNAClassDefinition.Fields Dim nField As Integer = -1 nField = pFields.FindField("Shape") If nField >= 0 Then Dim naFieldType As Integer = 0 naFieldType = pNAClassDefinition.FieldType("Shape") ' determining whether or not the shape field can be edited consists of running a bitwise comparison ' on the FieldType of the shape field. See the online help for a list of the possible field types. ' For our case, we want to verify that the shape field is an input field. If it is an input field, ' then we do NOT want to display the Add Item menu option. If ((naFieldType And CInt(esriNAFieldType.esriNAFieldTypeInput)) = CInt(esriNAFieldType.esriNAFieldTypeInput)) Then canEditShape = True Else canEditShape = False End If End If If (Not canEditShape) Then contextMenu1.MenuItems.Add(separator) contextMenu1.MenuItems.Add(miAddItem) End If End If contextMenu1.Show(Me, pt) ' even if the miAddItem menu item has not been added, Remove() won't crash. contextMenu1.MenuItems.Remove(separator) contextMenu1.MenuItems.Remove(miAddItem) Return True End Function Private Sub miLoadLocations_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles miLoadLocations.Click Dim mapControl As IMapControl3 = TryCast(axMapControl1.Object, IMapControl3) ' Show the Property Page form for ArcGIS Network Analyst extension Dim loadLocations As frmLoadLocations = New frmLoadLocations() If loadLocations.ShowModal(mapControl, m_naEnv) Then ' notify that the context has changed because we have added locations to a NAClass within it Dim contextEdit As INAContextEdit = TryCast(m_naEnv.NAWindow.ActiveAnalysis.Context, INAContextEdit) contextEdit.ContextChanged() ' If loaded locations, refresh the NAWindow and the Screen Dim naLayer As INALayer = m_naWindow.ActiveAnalysis mapControl.Refresh(esriViewDrawPhase.esriViewGeography, naLayer, mapControl.Extent) m_naWindow.UpdateContent(m_naWindow.ActiveCategory) End If End Sub Private Sub miClearLocations_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles miClearLocations.Click Dim mapControl As IMapControl3 = TryCast(axMapControl1.Object, IMapControl3) Dim naHelper As IEngineNetworkAnalystHelper = TryCast(m_naEnv, IEngineNetworkAnalystHelper) Dim naWindow As IEngineNAWindow = m_naWindow Dim naLayer As INALayer = naWindow.ActiveAnalysis ' we do not have to run ContextChanged() as with adding an item and loading locations, ' because that is done by the DeleteAllNetworkLocations method. naHelper.DeleteAllNetworkLocations() mapControl.Refresh(esriViewDrawPhase.esriViewGeography, naLayer, mapControl.Extent) End Sub Private Sub miAddItem_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles miAddItem.Click ' Developers Note: ' Once an item has been added, the user can double click on the item to edit the properties ' of the item. For the purposes of this sample, only the default values from the InitDefaultValues method ' and an auto generated Name value are populated initially for the new item. Dim mapControl As IMapControl3 = TryCast(axMapControl1.Object, IMapControl3) Dim activeCategory As IEngineNAWindowCategory2 = TryCast(m_naWindow.ActiveCategory, IEngineNAWindowCategory2) Dim pDataLayer As IDataLayer = activeCategory.DataLayer ' In order to add an item, we need to create a new row in the class and populate it ' with the initial default values for that class. Dim table As ITable = TryCast(pDataLayer, ITable) Dim row As IRow = table.CreateRow() Dim rowSubtypes As IRowSubtypes = TryCast(row, IRowSubtypes) rowSubtypes.InitDefaultValues() ' we need to auto generate a display name for the newly added item. ' In some cases (depending on how the schema is set up) InitDefaultValues may result in a nonempty name string ' in these cases do not override the preexisting non-empty name string with our auto generated one. Dim ipFeatureLayer As IFeatureLayer = TryCast(activeCategory.Layer, IFeatureLayer) Dim ipStandaloneTable As IStandaloneTable = TryCast(pDataLayer, IStandaloneTable) Dim name As String = "" If Not ipFeatureLayer Is Nothing Then name = ipFeatureLayer.DisplayField ElseIf Not ipStandaloneTable Is Nothing Then name = ipStandaloneTable.DisplayField End If ' If the display field is an empty string or does not represent an actual field on the NAClass just skip the auto generation. ' (Some custom solvers may not have set the DisplayField for example). ' Note: The name we are auto generating does not have any spaces in it. This is to ensure that that any classes ' that are space sensitive will be able to handle the name (ex Specialties). Dim currentName As String = "" Dim fieldIndex As Integer = row.Fields.FindField(name) If (fieldIndex >= 0) Then currentName = CType(row.Value(fieldIndex), String) If (currentName.Length <= 0) Then autogenInt += 1 row.Value(fieldIndex) = "Item" & autogenInt End If End If ' A special case is OrderPairs NAClass because that effectively has a combined 2 field display field. ' You will have to hard code to look for that NAClassName and create a default name for ' both first order and second order field names so the name will display correctly ' (look for the NAClass Name and NOT the layer name). Dim naClassDef As INAClassDefinition = activeCategory.NAClass.ClassDefinition If (naClassDef.Name = "OrderPairs") Then fieldIndex = row.Fields.FindField("SecondOrderName") If (fieldIndex >= 0) Then Dim secondName As String = CType(row.Value(fieldIndex), String) If (secondName.Length <= 0) Then autogenInt += 1 row.Value(fieldIndex) = "Item" & autogenInt End If End If End If row.Store() ' notify that the context has changed because we have added an item to a NAClass within it Dim contextEdit As INAContextEdit = CType(m_naEnv.NAWindow.ActiveAnalysis.Context, INAContextEdit) contextEdit.ContextChanged() ' refresh the NAWindow and the Screen Dim naLayer As INALayer = m_naWindow.ActiveAnalysis mapControl.Refresh(esriViewDrawPhase.esriViewGeography, naLayer, mapControl.Extent) m_naWindow.UpdateContent(m_naWindow.ActiveCategory) End Sub End Class End Namespace