Quaking code

After reviewing other earthquake map applications in the Windows Phone marketplace, I decided there wasn’t much for me to do as far as making a better earthquake map. Most of the complaints users have with the existing apps have to do with data, and there’s not much I can do about that.

That said, here’s the bad code I came up with to make my map work.

<my:Map Margin="0,0,0,0" Name="map1" CredentialsProvider="secretfrombing" ZoomBarVisibility="Visible" />

That’s all my XAML. Generally, in a Silverlight phone app, you’ll want more than that. Your view should contain everything needed to drive the view with databinding and your code behind should just be pulling data.

I didn’t realize you could databind pins in a map until I was trying to figure out how to make the pins clickable links (or I guess on the phone they are tappable).

        public MainPage()
        {
            InitializeComponent();
            LoadFeed();
        }

        private void LoadFeed()
        {
            WebClient webClient1 = new WebClient();
            webClient1.DownloadStringCompleted += new DownloadStringCompletedEventHandler(webClient1_DownloadStringCompleted);
            webClient1.DownloadStringAsync(new System.Uri("http://earthquake.usgs.gov/earthquakes/catalogs/eqs7day-M2.5.xml"));
        }

        private void webClient1_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                Deployment.Current.Dispatcher.BeginInvoke(() =&gt;
                {
                    MessageBox.Show("Failed to load basic feed.");
                });
            }
            else
            {
                this.State["feed1"] = e.Result;
                UpdateFeedList1(e.Result);
            }
        }

        private void UpdateFeedList1(string feedXML)
        {
            XElement xmlFeed = XElement.Parse(feedXML);

            XNamespace geo = "http://www.w3.org/2003/01/geo/wgs84_pos#";
            XNamespace dc = "http://purl.org/dc/elements/1.1/";

            var quakes = from item in xmlFeed.Descendants("channel").Descendants("item")
                         select new SyndicatedItem
                         {
                             Magnitude = double.Parse(item.Element("title").Value.Substring(2, 3)),
                             Lat = double.Parse(item.Element(geo + "lat").Value),
                             Long = double.Parse(item.Element(geo + "long").Value),
                             PublishDate = DateTime.Parse(item.Element("pubDate").Value),
                             Link = item.Element("link").Value
                         };

            foreach (var quake in quakes)
            {
                MapPin(quake.Lat, quake.Long, quake.Magnitude, quake.Magnitude.ToString(), quake.Link);
            }
        }

        public void MapPin(double lat, double lon, double mag, string content, string link)
        {
            var pin = new Pushpin();
            pin.Location = new GeoCoordinate(lat, lon);
            Color magColor;

            switch ((int)(Math.Floor(mag)))
            {
                case 0:
                    magColor = Colors.Gray;
                    break;
                case 1:
                    magColor = Colors.DarkGray;
                    break;
                case 2:
                    magColor = Colors.Magenta;
                    break;
                case 3:
                    magColor = Colors.Purple;
                    break;
                case 4:
                    magColor = Colors.Blue;
                    break;
                case 5:
                    magColor = Colors.Green;
                    break;
                case 6:
                    magColor = Colors.Yellow;
                    break;
                case 7:
                    magColor = Colors.Orange;
                    break;
                case 8:
                    magColor = Colors.Red;
                    break;
                case 9:
                    magColor = Colors.Black;
                    break;
                default:
                    magColor = Colors.Gray;
                    break;
            }

            pin.Background = new SolidColorBrush(magColor);
            pin.Content = content;
            pin.Tag = link;
            pin.Tap += new EventHandler&lt;GestureEventArgs&gt;(pin_Tap);
            map1.Children.Add(pin);
        }

        void pin_Tap(object sender, GestureEventArgs e)
        {
            var pin = sender as Pushpin;

            WebBrowserTask webBrowserTask = new WebBrowserTask();
            webBrowserTask.Uri = new Uri(pin.Tag.ToString());
            webBrowserTask.Show();
        }

And my SyndicatedItem class:

    public class SyndicatedItem
    {
        public DateTime PublishDate { get; set; }
        public double Magnitude { get; set; }
        public double Lat { get; set; }
        public double Long { get; set; }
        public string Link { get; set; }
    }

I create a new webclient and get the RSS xml asynchronously, when it comes back, I used LinqToXML to parse the file. Pay attention to how namespaces are handled. If you don’t declare the namespace as an object and concatenate it, it will not find the node you are looking for. I added a function that would add a pin to the screen so I could for-each over the result set to display the data on the map.

Each pin gets an event handler added to it for the tap event so the pin can link back to the web page with more details on the earthquake and I’m storing the URL in the tag property of the pin. If I was databinding the pins, I would simply refer back to the datamodel to get the URL.

Now that I’ve shown you the wrong way, here’s a blog post that shows a little better way to work with the map using databinding: http://igrali.wordpress.com/2012/01/07/show-a-tooltip-for-tapped-pushpin-on-windows-phone/.

Earthquakes!

Was trying to come up with a fun Windows Phone app idea when I found some RSS feeds of recent earthquakes published by the US government (you can check them out here: http://earthquake.usgs.gov/earthquakes/catalogs/). I don’t know how useful such an app would be, but it seems like an interesting way to learn about the map controls.

Naming my project “Earthquakes” has an amusing side effect, when I send a new build to the emulator, I get to “Deploy Earthquakes.”

Update (one hour later)!

I’ve got a map parsing live data from the RSS feed and popping color-coded pins (based on magnitude) all over the map.