Managing common code on Windows 7 (.NET) and Windows 8 (WinRT)

Posted by ryanabr on Geeks with Blogs See other posts from Geeks with Blogs or by ryanabr
Published on Thu, 21 Jun 2012 10:40:02 GMT Indexed on 2012/06/21 21:16 UTC
Read the original article Hit count: 280

Filed under:

Recent announcements regarding Windows Phone 8 and the fact that it will have the WinRT behind it might make some of this less painful but I  discovered the "XmlDocument" object is in a new location in WinRT and is almost the same as it's brother in .NET

  • System.Xml.XmlDocument (.NET)
  • Windows.Data.Xml.Dom.XmlDocument (WinRT)

The problem I am trying to solve is how to work with both types in the code that performs the same task on both Windows Phone 7 and Windows 8 platforms. The first thing I did was define my own XmlNode and XmlNodeList classes that wrap the actual Microsoft objects so that by using the "#if" compiler directive either work with the WinRT version of the type, or the .NET version from the calling code easily.

  1. public class XmlNode
  2.     {
  3. #if WIN8
  4.         public Windows.Data.Xml.Dom.IXmlNode Node { get; set; }
  5.         public XmlNode(Windows.Data.Xml.Dom.IXmlNode xmlNode)
  6.         {
  7.             Node = xmlNode;
  8.         }
  9. #endif
  10. #if !WIN8
  11. public System.Xml.XmlNode Node { get; set ; }
  12. public XmlNode(System.Xml.XmlNode xmlNode)
  13.         {
  14.             Node = xmlNode;
  15.         }
  16. #endif
  17.     }
  18. public class XmlNodeList
  19.     {
  20. #if WIN8
  21.         public Windows.Data.Xml.Dom.XmlNodeList List { get; set; }
  22.         public int Count {get {return (int)List.Count;}}
  23.         public XmlNodeList(Windows.Data.Xml.Dom.XmlNodeList list)
  24.         {
  25.             List = list;
  26.         }
  27. #endif
  28. #if !WIN8
  29. public System.Xml.XmlNodeList List { get; set ; }
  30. public int Count { get { return List.Count;}}
  31. public XmlNodeList(System.Xml.XmlNodeList list)
  32.         {
  33.             List = list;
  34.        }
  35. #endif
  36.     }

From there I can then use my XmlNode and XmlNodeList in the calling code with out having to clutter the code with all of the additional #if switches. The challenge after this was the code that worked directly with the XMLDocument object needed to be seperate on both platforms since the method for populating the XmlDocument object is completly different on both platforms.

To solve this issue. I made partial classes, one partial class for .NET and one for WinRT. Both projects have Links to the Partial Class that contains the code that is the same for the majority of the class, and the partial class contains the code that is unique to the version of the XmlDocument.

SolutionExplorer

The files with the little arrow in the lower left corner denotes 'linked files' and are shared in multiple projects but only exist in one location in source control. You can see that the _Win7 partial class is included directly in the project since it include code that is only for the .NET platform, where as it's cousin the _Win8 (not pictured above) has all of the code specific to the _Win8 platform.

In the _Win7 partial class is this code:

  1. public partial class WUndergroundViewModel
  2.     {
  3. public static WUndergroundData GetWeatherData( double lat, double lng)
  4.         {
  5. WUndergroundData data = new WUndergroundData();
  6.             System.Net. WebClient c = new System.Net. WebClient();
  7. string req = "http://api.wunderground.com/api/xxx/yesterday/conditions/forecast/q/[LAT],[LNG].xml" ;
  8.             req = req.Replace( "[LAT]" , lat.ToString());
  9.             req = req.Replace( "[LNG]" , lng.ToString());
  10. XmlDocument doc = new XmlDocument();
  11.             doc.Load(c.OpenRead(req));
  12. foreach (XmlNode item in doc.SelectNodes("/response/features/feature" ))
  13.             {
  14. switch (item.Node.InnerText)
  15.                 {
  16. case "yesterday" :
  17.                         ParseForecast( new FishingControls.XmlNodeList (doc.SelectNodes( "/response/forecast/txt_forecast/forecastdays/forecastday" )),
  18. new FishingControls.XmlNodeList (doc.SelectNodes( "/response/forecast/simpleforecast/forecastdays/forecastday" )), data);
  19. break ;
  20. case "conditions" :
  21.                         ParseCurrent( new FishingControls.XmlNode (doc.SelectSingleNode("/response/current_observation" )), data);
  22. break ;
  23. case "forecast" :
  24.                         ParseYesterday( new FishingControls.XmlNodeList (doc.SelectNodes( "/response/history/observations/observation" )),data);
  25. break ;
  26.                 }
  27.             }
  28. return data;
  29.         }
  30.     }

in _win8 partial class is this code:

  1. public partial class WUndergroundViewModel
  2.     {
  3. public async static Task< WUndergroundData > GetWeatherData(double lat, double lng)
  4.         {
  5. WUndergroundData data = new WUndergroundData ();
  6. HttpClient c = new HttpClient ();
  7. string req = "http://api.wunderground.com/api/xxxx/yesterday/conditions/forecast/q/[LAT],[LNG].xml" ;
  8.             req = req.Replace( "[LAT]" , lat.ToString());
  9.             req = req.Replace( "[LNG]" , lng.ToString());
  10. HttpResponseMessage msg = await c.GetAsync(req);
  11. string stream = await msg.Content.ReadAsStringAsync();
  12. XmlDocument doc = new XmlDocument ();
  13.             doc.LoadXml(stream, null);
  14. foreach ( IXmlNode item in doc.SelectNodes("/response/features/feature" ))
  15.             {
  16. switch (item.InnerText)
  17.                 {
  18. case "yesterday" :
  19.                         ParseForecast( new FishingControls.XmlNodeList (doc.SelectNodes( "/response/forecast/txt_forecast/forecastdays/forecastday" )),
  20. new FishingControls.XmlNodeList (doc.SelectNodes( "/response/forecast/simpleforecast/forecastdays/forecastday" )), data);
  21. break;
  22. case "conditions" :
  23.                         ParseCurrent( new FishingControls.XmlNode (doc.SelectSingleNode("/response/current_observation" )), data);
  24. break;
  25. case "forecast" :
  26.                         ParseYesterday( new FishingControls.XmlNodeList (doc.SelectNodes( "/response/history/observations/observation")), data);
  27. break;
  28.                 }
  29.             }
  30. return data;
  31.         }
  32.     }

Summary:

This method allows me to have common 'business' code for both platforms that is pretty clean, and I manage the technology differences separately. Thank you tostringtheory for your suggestion, I was considering that approach.

© Geeks with Blogs or respective owner