GeoNames Find
FindDockWindow.vb
' Copyright 2011 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.
' 

' Copyright 2010 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 at <your ArcGIS Explorer install location>/DeveloperKit/userestrictions.txt.
' 

Imports Microsoft.VisualBasic
Imports System
Imports System.ComponentModel
Imports System.IO
Imports System.Net
Imports System.Linq
Imports System.Windows.Forms
Imports System.Xml

Imports ESRI.ArcGISExplorer.Application
Imports ESRI.ArcGISExplorer.Mapping
Imports ESRI.ArcGISExplorer.Geometry
Imports ESRI.ArcGISExplorer.Data

''' <summary>
''' Implements a custom find DockWindow.
''' </summary>
''' <remarks>
''' Uses the geonames web service to search for placenames. The web service takes
''' a URL query and returns an XML file with the results.
''' The results are parsed and Graphics are created from them. The Graphics are attached
''' to the Tag property of the TreeNode and are drawn on the map when the node is checked.
''' </remarks>
Public Class FindDockWindowVB
    Inherits ESRI.ArcGISExplorer.Application.DockWindow
    Private _webClient As WebClient ' used to download results from the web service
    Private _resultFile As String ' temp file that contains the result xml
    Private _graphics As GraphicCollection = Nothing
    ''' <summary>
    ''' Creates a new FindDockWindow instance.
    ''' </summary>
    Public Sub New()
        InitializeComponent()

        _webClient = New WebClient()
        AddHandler _webClient.DownloadFileCompleted, AddressOf _webClient_DownloadCompleted
    End Sub

#Region "Button Events"

    ''' <summary>
    ''' Raised when the Clear button is clicked. 
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    Private Sub buttonClear_Click(ByVal sender As Object, ByVal e As EventArgs) Handles buttonClear.Click
        ClearResults()
    End Sub

    ''' <summary>
    ''' Clears the results from the tree.
    ''' </summary>
    Private Sub ClearResults()
        For Each node As TreeNode In treeView1.Nodes
            node.Checked = False ' causes the associated graphic to be removed from the map
        Next node

        treeView1.Nodes.Clear()
    End Sub

    ''' <summary>
    ''' Enables/disables the controls on the DockWindow.
    ''' </summary>
    ''' <param name="enable"></param>
    Private Sub EnableControls(ByVal enable As Boolean)
        buttonFind.Enabled = enable
        buttonClear.Enabled = enable
        textBox1.Enabled = enable

        ' if we are enabling the controls, select the search string 
        ' and give the TextBox focus
        '
        If enable Then
            textBox1.SelectAll()
            textBox1.Focus()
        End If
    End Sub

    ''' <summary>
    ''' Raised when the Find button is clicked. Issues the query to the web service.
    ''' </summary>
    Private Sub buttonFind_Click(ByVal sender As Object, ByVal e As EventArgs) Handles buttonFind.Click
        ClearResults()
        EnableControls(False)

        ' generate a temporary filename to hold the result
        '
        _resultFile = Path.GetTempFileName()

        ' build the url and make the async call to execute the query (just get the first 10 matches)
        '
        Dim url As String = "http://ws.geonames.org/search?q=" & textBox1.Text & "&maxRows=10&style=full"
        _webClient.DownloadFileAsync(New Uri(url), _resultFile)
    End Sub

#End Region

#Region "WebClient Events"

    ''' <summary>
    ''' Raised when the xml result file has been downloaded.
    ''' </summary>
    Private Sub _webClient_DownloadCompleted(ByVal sender As Object, ByVal e As AsyncCompletedEventArgs)
        ' read the xml file
        '
        Dim doc As XmlDocument = New XmlDocument()
        doc.Load(_resultFile)

        For Each xmlNode As XmlNode In doc.SelectNodes("/geonames/geoname")
            Dim lat As Double = Double.Parse(xmlNode.SelectSingleNode("lat").InnerText)
            Dim lon As Double = Double.Parse(xmlNode.SelectSingleNode("lng").InnerText)
            Dim elev As Double = Double.NaN

            Double.TryParse(xmlNode.SelectSingleNode("elevation").InnerText, elev)

            Dim graphic As Graphic = CreateGraphic(xmlNode.SelectSingleNode("name").InnerText, xmlNode.SelectSingleNode("adminName1").InnerText, xmlNode.SelectSingleNode("countryName").InnerText, lat, lon, elev)

            Dim treeNode As New TreeNode(graphic.Label)
            treeNode.Tag = graphic
            treeView1.Nodes.Add(treeNode)
        Next xmlNode

        EnableControls(True)

        ' zoom to the first node in the tree
        '
        If treeView1.Nodes.Count > 0 Then
            ZoomTo(treeView1.Nodes(0))
        End If
    End Sub

    ''' <summary>
    ''' Zooms to the location that corresponds to the specified TreeNode and makes it visible.
    ''' </summary>
    ''' <param name="item"></param>
    Private Sub ZoomTo(ByVal node As TreeNode)

        node.Checked = True
        Me.Update() ' force redraw of the DockView before the flying to the item

        Me.Cursor = Cursors.AppStarting
        ESRI.ArcGISExplorer.Application.Application.ActiveMapDisplay.ZoomTo((TryCast(node.Tag, Graphic)).Geometry.GetEnvelope())
        Me.Cursor = Cursors.Default
    End Sub

    ''' <summary>
    ''' Creates a Graphic using the specified names and location.
    ''' </summary>
    Private Function CreateGraphic(ByVal name As String, ByVal adminName As String, ByVal countryName As String, ByVal lat As Double, ByVal lon As Double, ByVal elev As Double) As Graphic
        Dim graphic As Graphic = New Graphic(New ESRI.ArcGISExplorer.Geometry.Point(lon, lat, elev), Symbol.Marker.Stickpin.White)

        If Double.IsNaN(elev) Then ' is the elevation undefined?
            graphic.Placement3D = Placement3D.AttachToSurface
        Else
            graphic.Placement3D = Placement3D.AbsoluteElevation
        End If

        If (Not String.IsNullOrEmpty(adminName)) Then
            name &= ", " & adminName
        End If

        If (Not String.IsNullOrEmpty(countryName)) Then
            name &= ", " & countryName
        End If

        graphic.Label = name

        Return graphic
    End Function

#End Region

#Region "TreeView Events"

    ''' <summary>
    ''' Raised when a TreeNode is checked or unchecked.
    ''' </summary>
    Private Sub treeView1_AfterCheck(ByVal sender As Object, ByVal e As TreeViewEventArgs) Handles treeView1.AfterCheck

        Dim _graphics As GraphicCollection = ESRI.ArcGISExplorer.Application.Application.ActiveMapDisplay.Graphics
        Dim g As Graphic = TryCast(e.Node.Tag, Graphic)

        If _graphics.Contains(g) Then
            g.Visible = e.Node.Checked
        Else
            _graphics.Add(g)
        End If

    End Sub

    ''' <summary>
    ''' Raised when an tree node is double-clicked.
    ''' </summary>

    Private Sub treeView1_NodeMouseDoubleClick(ByVal sender As Object, ByVal e As TreeNodeMouseClickEventArgs) Handles treeView1.NodeMouseDoubleClick
        ZoomTo(e.Node)
    End Sub

#End Region

#Region "TextBox Events"
    ''' <summary>
    ''' Raised when a key is pressed in the TextBox control.
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    Private Sub textBox1_KeyDown(ByVal sender As Object, ByVal e As KeyEventArgs) Handles textBox1.KeyDown
        If e.KeyCode = Keys.Return Then
            e.Handled = True
            buttonFind_Click(Me, EventArgs.Empty)
        End If
    End Sub

#End Region

#Region "Context Menu Events"

    ''' <summary>
    ''' Delete context menu item.
    ''' </summary>
    Private Sub deleteMenuItem_Click(ByVal sender As Object, ByVal e As EventArgs) Handles deleteMenuItem.Click
        If treeView1.SelectedNode.Checked Then
            treeView1.SelectedNode.Checked = False
        End If

        treeView1.SelectedNode.Remove()
    End Sub

    ''' <summary>
    ''' Move To Map context menu item - creates a note for the selected
    ''' TreeNode and adds it to the map.
    ''' </summary>
    Private Sub moveToMapMenuItem_Click(ByVal sender As Object, ByVal e As EventArgs) Handles moveToMapMenuItem.Click
        Dim map As Map = ESRI.ArcGISExplorer.Application.Application.ActiveMapDisplay.Map

        treeView1.SelectedNode.Checked = False ' causes the associated graphic to be removed from the map


        Dim graphic As Graphic = TryCast(treeView1.SelectedNode.Tag, Graphic)
        Dim note As Note = New Note(graphic.Label, graphic.Geometry, Symbol.Marker.Stickpin.Orange) ' change the symbol
        note.Viewpoint = New Viewpoint(graphic.Geometry.GetEnvelope())

        map.ChildItems.Insert(0, note) ' add the note to the map
        ESRI.ArcGISExplorer.Application.Application.SelectedItems.Select(note)

        treeView1.SelectedNode.Remove()
    End Sub

    ''' <summary>
    ''' Delete All context menu item.
    ''' </summary>
    Private Sub deleteAllMenuItem_Click(ByVal sender As Object, ByVal e As EventArgs) Handles deleteAllMenuItem.Click
        ClearResults()
    End Sub

    ''' <summary>
    ''' Raised before the context menu is shown - enable/disable items.
    ''' </summary>
    Private Sub contextMenuStrip1_Opening(ByVal sender As Object, ByVal e As CancelEventArgs) Handles contextMenu.Opening
        ' enable/disable the context menu items
        deleteMenuItem.Enabled = Not treeView1.SelectedNode Is Nothing
        moveToMapMenuItem.Enabled = Not treeView1.SelectedNode Is Nothing
        deleteAllMenuItem.Enabled = treeView1.Nodes.Count > 0
    End Sub
#End Region

End Class