FindDockWindow.cs
// 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. // using System; using System.ComponentModel; using System.IO; using System.Linq; using System.Net; using System.Windows.Forms; using System.Xml; using ESRI.ArcGISExplorer.Mapping; namespace GeoNamesFind { /// <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 partial class FindDockWindow : ESRI.ArcGISExplorer.Application.DockWindow { WebClient _webClient; // used to download results from the web service string _resultFile; // temp file that contains the result xml GraphicCollection _graphics = null; /// <summary> /// Creates a new FindDockWindow instance. /// </summary> public FindDockWindow() { InitializeComponent(); _webClient = new WebClient(); _webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(_webClient_DownloadCompleted); _graphics = ESRI.ArcGISExplorer.Application.Application.ActiveMapDisplay.Graphics; } #region Button Events /// <summary> /// Raised when the Clear button is clicked. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void buttonClear_Click(object sender, EventArgs e) { ClearResults(); } /// <summary> /// Clears the results from the tree and graphics from the map. /// </summary> void ClearResults() { foreach (TreeNode node in treeView1.Nodes) { _graphics.Remove(node.Tag as Graphic); } treeView1.Nodes.Clear(); } /// <summary> /// Enables/disables the controls on the DockWindow. /// </summary> /// <param name="enable"></param> void EnableControls(bool enable) { 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) { textBox1.SelectAll(); textBox1.Focus(); } } /// <summary> /// Raised when the Find button is clicked. Issues the query to the web service. /// </summary> private void buttonFind_Click(object sender, EventArgs e) { 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) // string url = "http://ws.geonames.org/search?q=" + textBox1.Text + "&maxRows=10&style=full"; _webClient.DownloadFileAsync(new Uri(url), _resultFile); } #endregion #region WebClient Events /// <summary> /// Raised when the xml result file has been downloaded. /// </summary> void _webClient_DownloadCompleted(object sender, AsyncCompletedEventArgs e) { // read the xml file // XmlDocument doc = new XmlDocument(); doc.Load(_resultFile); foreach (XmlNode xmlNode in doc.SelectNodes("/geonames/geoname")) { double lat = double.Parse(xmlNode.SelectSingleNode("lat").InnerText); double lon = double.Parse(xmlNode.SelectSingleNode("lng").InnerText); double elev = double.NaN; double.TryParse(xmlNode.SelectSingleNode("elevation").InnerText, out elev); Graphic graphic = CreateGraphic(xmlNode.SelectSingleNode("name").InnerText, xmlNode.SelectSingleNode("adminName1").InnerText, xmlNode.SelectSingleNode("countryName").InnerText, lat, lon, elev); treeView1.Nodes.Add(new TreeNode(graphic.Label) { Tag = graphic }); } EnableControls(true); // zoom to the first node in the tree // if (treeView1.Nodes.Count > 0) ZoomTo(treeView1.Nodes[0]); } /// <summary> /// Zooms to the location that corresponds to the specified TreeNode and makes it visible. /// </summary> /// <param name="item"></param> void ZoomTo(TreeNode node) { node.Checked = true; this.Update(); // force redraw of the DockView before the flying to the item this.Cursor = Cursors.AppStarting; Graphic g = node.Tag as Graphic; if (g != null) ESRI.ArcGISExplorer.Application.Application.ActiveMapDisplay.ZoomTo(g.Geometry); this.Cursor = Cursors.Default; } /// <summary> /// Creates a Graphic using the specified names and location. /// </summary> Graphic CreateGraphic(string name, string adminName, string countryName, double lat, double lon, double elev) { Graphic graphic = new Graphic(new ESRI.ArcGISExplorer.Geometry.Point(lon, lat, elev), Symbol.Marker.Stickpin.White); if (double.IsNaN(elev)) // is the elevation undefined? graphic.Placement3D = Placement3D.AttachToSurface; else graphic.Placement3D = Placement3D.AbsoluteElevation; if (!string.IsNullOrEmpty(adminName)) name += ", " + adminName; if (!string.IsNullOrEmpty(countryName)) name += ", " + countryName; graphic.Label = name; return graphic; } #endregion #region TreeView Events /// <summary> /// Raised when a TreeNode is checked or unchecked. /// </summary> private void treeView1_AfterCheck(object sender, TreeViewEventArgs e) { Graphic g = e.Node.Tag as Graphic; if (g == null) return; // if the node is checked, show the graphic on the map, otherwise, hide it. if (_graphics.Contains(g)) { g.Visible = (e.Node.Checked); } else { // If this is the first time that the graphic is shown, then add it to the Map. // It will be visible by default. _graphics.Add(g); } } /// <summary> /// Raised when an tree node is double-clicked. /// </summary> private void treeView1_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e) { ZoomTo(e.Node); } #endregion #region TextBox Events /// <summary> /// Raised when a key is pressed in the TextBox control. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void textBox1_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Return) { e.Handled = true; buttonFind_Click(this, EventArgs.Empty); } } #endregion #region Context Menu Events /// <summary> /// Delete context menu item. /// </summary> private void deleteMenuItem_Click(object sender, EventArgs e) { if (treeView1.SelectedNode == null) return; // Remove tree node and associated graphic from the map. Graphic g = treeView1.SelectedNode.Tag as Graphic; if (g != null) _graphics.Remove(g); treeView1.SelectedNode.Remove(); } /// <summary> /// Move To Map context menu item - creates a note for the selected /// TreeNode and adds it to the map. /// </summary> private void moveToMapMenuItem_Click(object sender, EventArgs e) { if (treeView1.SelectedNode == null) return; Map map = ESRI.ArcGISExplorer.Application.Application.ActiveMapDisplay.Map; Graphic g = treeView1.SelectedNode.Tag as Graphic; treeView1.SelectedNode.Checked = false; // causes the associated graphic to be removed from the map _graphics.Remove(g); if (g != null) { Note note = new Note(g.Label, g.Geometry, Symbol.Marker.Stickpin.Orange); // change the symbol note.Viewpoint = new Viewpoint(g.Geometry.GetEnvelope()); map.ChildItems.Insert(0, note); // add the note to the map ESRI.ArcGISExplorer.Application.Application.SelectedItems.Select(note); } treeView1.SelectedNode.Remove(); } /// <summary> /// Delete All context menu item. /// </summary> private void deleteAllMenuItem_Click(object sender, EventArgs e) { ClearResults(); } /// <summary> /// Raised before the context menu is shown - enable/disable items. /// </summary> private void contextMenuStrip1_Opening(object sender, CancelEventArgs e) { // enable/disable the context menu items deleteMenuItem.Enabled = treeView1.SelectedNode != null; moveToMapMenuItem.Enabled = treeView1.SelectedNode != null; deleteAllMenuItem.Enabled = treeView1.Nodes.Count > 0; } #endregion } }