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()

        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.");
                this.State["feed1"] = 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;
                case 1:
                    magColor = Colors.DarkGray;
                case 2:
                    magColor = Colors.Magenta;
                case 3:
                    magColor = Colors.Purple;
                case 4:
                    magColor = Colors.Blue;
                case 5:
                    magColor = Colors.Green;
                case 6:
                    magColor = Colors.Yellow;
                case 7:
                    magColor = Colors.Orange;
                case 8:
                    magColor = Colors.Red;
                case 9:
                    magColor = Colors.Black;
                    magColor = Colors.Gray;

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

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

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

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/.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s