Wednesday, February 20, 2013

WP7 - Weather App in Window Phone 7

In this article i will explain how to create a basic Weather app in window phone 7 using XML data World Weather Online (API) service.

In this Example we get and display the weather in the user's specified location. We can search for weather based on the get the based on city name,state and also specify the how many days weather information should return (we get only minimum five days weather information including current day).

Let see how to create Weather app in Window Phone 7.

Step 1
First we need to register following website for generating API Key.
http://www.worldweatheronline.com/register.aspx 

Step 2
To Develop application for Windows Phone 7 devices, we need to install Windows Phone 7.1 SDK.We can download latest SDK for Windows Phone
http://www.microsoft.com/en-us/download/details.aspx?displaylang=en&id=27570

SDK 7.1.1 Update
https://dev.windowsphone.com/en-us/downloadsdk

Step 3

Create a Window Phone Application and give the solution name as SolWeatherApp.

To start creating a new Windows Phone application, start Microsoft Visual Studio then create a new Project and select Windows Phone Application Template,it is look like this



Click on Image for better View

Step 4
Select the Window Phone Platform,it is look like this



Click on Image for better View

Step 5
Add a System.Xml.Linq Assemble reference to the project.Right click on the project name in Solution Explorer, select Add Reference and Select System.Xml.Linq  and select OK button,it is look like this



Click on Image for better View

Step 6
Let make a weather app XAML design, This design divided into three section,it is look like this

  • Search Box
  • Current Weather Information
  • Five Days Weather information

First create three Row on Content Panel Grid it is look like this   
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
			<Grid.RowDefinitions>
				<RowDefinition Height="0.126*"/>
				<RowDefinition Height="0.23*"/>
				<RowDefinition Height="0.644*"/>
			</Grid.RowDefinitions>	

</Grid>


Now create search box Inside Content panel Grid,it is look like this
<Grid x:Name="GSearchBox" Grid.Row="0" Grid.Column="0">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="317*" />
                    <ColumnDefinition Width="139*" />
                </Grid.ColumnDefinitions>


                <TextBox x:Name="txtSearchCity" Grid.Row="0" Grid.Column="0" Height="75"/>
                <Button x:Name="btnGo" Grid.Row="0" Grid.Column="1" Content="GO" Height="75" Click="btnGo_Click" />

            </Grid>


Add a controls for display current weather information Inside Content panel Grid,it is look like this
<Grid x:Name="GCurrentWeather" Grid.Row="1" Grid.Column="0">
				<Grid.ColumnDefinitions>
					<ColumnDefinition Width="150*"/>
					<ColumnDefinition Width="300*"/>
				</Grid.ColumnDefinitions>
				<Grid.RowDefinitions>
					<RowDefinition Height="0.25*"/>
					<RowDefinition Height="0.25*"/>
					<RowDefinition Height="0.25*"/>
					<RowDefinition Height="0.25*"/>
				</Grid.RowDefinitions>

                <Image Grid.Row="0" Grid.Column="0" Grid.RowSpan="4" Source="{Binding WeatherIconUrl}" Stretch="Fill" Height="120" Width="120" HorizontalAlignment="Center"></Image>
                <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Temperature,StringFormat='Temperature: \{0\} °C'}" FontSize="22" Margin="25,0,0,0"></TextBlock>
                <TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding ObservationTime,StringFormat='Observ.Time: \{0\}'}" FontSize="22" Margin="25,0,0,0"></TextBlock>
                <TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding Humidity,StringFormat='Humidity: \{0\} %'}" FontSize="22" Margin="25,0,0,0"></TextBlock>
                <TextBlock Grid.Row="3" Grid.Column="1" Text="{Binding WindSpeedKmph,StringFormat='Wind Speed: \{0\} Kmph'}" FontSize="22" Margin="25,0,0,0"></TextBlock>	

			</Grid>


Add a stack panel (Header) and List Box for display Five days weather information Inside Content panel Grid,it is look like this
<Grid x:Name="GWeather" Grid.Row="2" Grid.Column="0" Visibility="Visible">
				<Grid.RowDefinitions>
					<RowDefinition Height="0.107*"/>
					<RowDefinition Height="0.893*"/>
				</Grid.RowDefinitions>
				        
                        <!-- Display Header -->
						<StackPanel Grid.Row="0" Orientation="Horizontal" VerticalAlignment="Center" Margin="0,0,0,0">
                            <TextBlock Text="Date" FontSize="22" TextAlignment="Left" Width="170" Foreground="OrangeRed"/>
                    <TextBlock Text="FC" FontSize="22" TextAlignment="Left" Width="60" Foreground="OrangeRed"/>
                    <TextBlock Text="Max" FontSize="22" TextAlignment="Right" Width="90" Foreground="OrangeRed"/>
                    <TextBlock Text="Min" FontSize="22" TextAlignment="Right" Width="110" Foreground="OrangeRed"/>
                        </StackPanel>
				        
                        <!-- Display Five Days Weather info -->
				        <ListBox x:Name="LstWeather" Grid.Row="1" Grid.Column="0" ItemTemplate="{StaticResource WeatherDataTemplate}" ItemsSource="{Binding}"></ListBox>
				
			</Grid>

Now create a DataTemplate for List Box.The below template is used to show five day forecast. Each row is showing Date, Image and maximum and minimum temperature,it is look like this
<phone:PhoneApplicationPage.Resources>
		<DataTemplate x:Key="WeatherDataTemplate">
			 <StackPanel Height="40" Orientation="Horizontal" Margin="0,10,0,0">
                <TextBlock Text="{Binding Date}" FontSize="22" TextAlignment="Left" Width="150"/>
                <TextBlock Text="   " FontSize="20"/>
                <Image Source="{Binding WeatherIconUrl}" Width="40" Height="40"/>
                <TextBlock Text="   " FontSize="20"/>
                <TextBlock Text="{Binding TemperatureMaxC, StringFormat='\{0\} °C'}" FontSize="22" TextAlignment="Right" Width="100"/>
                <TextBlock Text="   " FontSize="20"/>
                <TextBlock Text="{Binding TemperatureMinC, StringFormat='\{0\} °C'}" FontSize="22" TextAlignment="Right" Width="100"/>
            </StackPanel>
		</DataTemplate>
	</phone:PhoneApplicationPage.Resources>



Click on Image for better View

Now Hide Gwether Grid Control,Set Visibility Property as Collapsed,it is look like this
<Grid x:Name="GWeather" Grid.Row="2" Grid.Column="0" Visibility="Collapsed">


Full XAML Code
<phone:PhoneApplicationPage
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
	xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
	xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
	xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
	mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
	x:Class="SolWeatherApp.MainPage"
	FontFamily="{StaticResource PhoneFontFamilyNormal}"
	FontSize="{StaticResource PhoneFontSizeNormal}"
	Foreground="{StaticResource PhoneForegroundBrush}"
	SupportedOrientations="Portrait" Orientation="Portrait"
	shell:SystemTray.IsVisible="True">
	<phone:PhoneApplicationPage.Resources>
		<DataTemplate x:Key="WeatherDataTemplate">
			 <StackPanel Height="40" Orientation="Horizontal" Margin="0,10,0,0">
                <TextBlock Text="{Binding Date}" FontSize="22" TextAlignment="Left" Width="150"/>
                <TextBlock Text="   " FontSize="20"/>
                <Image Source="{Binding WeatherIconUrl}" Width="40" Height="40"/>
                <TextBlock Text="   " FontSize="20"/>
                <TextBlock Text="{Binding TemperatureMaxC, StringFormat='\{0\} °C'}" FontSize="22" TextAlignment="Right" Width="100"/>
                <TextBlock Text="   " FontSize="20"/>
                <TextBlock Text="{Binding TemperatureMinC, StringFormat='\{0\} °C'}" FontSize="22" TextAlignment="Right" Width="100"/>
            </StackPanel>
		</DataTemplate>
	</phone:PhoneApplicationPage.Resources>

	<!--LayoutRoot is the root grid where all page content is placed-->
	<Grid x:Name="LayoutRoot" Background="Transparent">
		<Grid.RowDefinitions>
			<RowDefinition Height="Auto"/>
			<RowDefinition Height="*"/>
		</Grid.RowDefinitions>

		<!--TitlePanel contains the name of the application and page title-->
		<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
			<TextBlock x:Name="ApplicationTitle" Text="WEATHER APPLICATION" Style="{StaticResource PhoneTextNormalStyle}"/>		
		</StackPanel>

		<!--ContentPanel - place additional content here-->
		<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
			<Grid.RowDefinitions>
				<RowDefinition Height="0.126*"/>
				<RowDefinition Height="0.23*"/>
				<RowDefinition Height="0.644*"/>
			</Grid.RowDefinitions>		
			
            <Grid x:Name="GSearchBox" Grid.Row="0" Grid.Column="0">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="317*" />
                    <ColumnDefinition Width="139*" />
                </Grid.ColumnDefinitions>


                <TextBox x:Name="txtSearchCity" Grid.Row="0" Grid.Column="0" Height="75"/>
                <Button x:Name="btnGo" Grid.Row="0" Grid.Column="1" Content="GO" Height="75" Click="btnGo_Click" />

            </Grid>
            
			<Grid x:Name="GCurrentWeather" Grid.Row="1" Grid.Column="0">
				<Grid.ColumnDefinitions>
					<ColumnDefinition Width="150*"/>
					<ColumnDefinition Width="300*"/>
				</Grid.ColumnDefinitions>
				<Grid.RowDefinitions>
					<RowDefinition Height="0.25*"/>
					<RowDefinition Height="0.25*"/>
					<RowDefinition Height="0.25*"/>
					<RowDefinition Height="0.25*"/>
				</Grid.RowDefinitions>

                <Image Grid.Row="0" Grid.Column="0" Grid.RowSpan="4" Source="{Binding WeatherIconUrl}" Stretch="Fill" Height="120" Width="120" HorizontalAlignment="Center"></Image>
                <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Temperature,StringFormat='Temperature: \{0\} °C'}" FontSize="22" Margin="25,0,0,0"></TextBlock>
                <TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding ObservationTime,StringFormat='Observ.Time: \{0\}'}" FontSize="22" Margin="25,0,0,0"></TextBlock>
                <TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding Humidity,StringFormat='Humidity: \{0\} %'}" FontSize="22" Margin="25,0,0,0"></TextBlock>
                <TextBlock Grid.Row="3" Grid.Column="1" Text="{Binding WindSpeedKmph,StringFormat='Wind Speed: \{0\} Kmph'}" FontSize="22" Margin="25,0,0,0"></TextBlock>	

			</Grid>
			
            <Grid x:Name="GWeather" Grid.Row="2" Grid.Column="0" Visibility="Collapsed">
				<Grid.RowDefinitions>
					<RowDefinition Height="0.107*"/>
					<RowDefinition Height="0.893*"/>
				</Grid.RowDefinitions>
				        
                        <!-- Display Header -->
						<StackPanel Grid.Row="0" Orientation="Horizontal" VerticalAlignment="Center" Margin="0,0,0,0">
                            <TextBlock Text="Date" FontSize="22" TextAlignment="Left" Width="170" Foreground="OrangeRed"/>
                    <TextBlock Text="FC" FontSize="22" TextAlignment="Left" Width="60" Foreground="OrangeRed"/>
                    <TextBlock Text="Max" FontSize="22" TextAlignment="Right" Width="90" Foreground="OrangeRed"/>
                    <TextBlock Text="Min" FontSize="22" TextAlignment="Right" Width="110" Foreground="OrangeRed"/>
                        </StackPanel>
				        
                        <!-- Display Five Days Weather info -->
				        <ListBox x:Name="LstWeather" Grid.Row="1" Grid.Column="0" ItemTemplate="{StaticResource WeatherDataTemplate}" ItemsSource="{Binding}"></ListBox>
				
			</Grid>
			
		</Grid>
	</Grid>
</phone:PhoneApplicationPage>


Finally design part is finished.Lets move to code behind section.

Step 7
Create a WeatherEntity Class.Weather Online offers lots of different weather information but  i used only those entity which i want to display in this example.Just Check the XML data which come from API and according to that create a Entity,it is look like this
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace SolWeatherApp
{
    public class WeatherEntity
    {
        #region Property
        
        public String ObservationTime
        {
            get;
            set;
        }

        public String Date
        {
            get;
            set;
        }

        public String Temperature
        {
            get;
            set;
        }

        public String TemperatureMaxC
        {
            get;
            set;
        }

        public String TemperatureMinC
        {
            get;
            set;
        }
        
        public String WindSpeedKmph
        {
            get;
            set;
        }

        public String Humidity
        {
            get;
            set;
        }

        public String WeatherIconUrl
        {
            get;
            set;
        }
        #endregion
    }
}

Step 8
Create a two method in weather static class for retrieving data from XML.One method should return current date of weather information and another method should return the five days of weather information,it is look like this  
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;

namespace SolWeatherApp
{
    public static class Weather
    {
        #region Method

        /// <summary>
        /// Get Current Weather Data
        /// </summary>
        /// <param name="APIResultSet">Specify the Result Object which data come from Weather API</param>
        /// <returns>WeatherEntity</returns>
        public static WeatherEntity GetCurrentWeatherData(String APIResultSet)
        {
            try
            {
                XDocument XDocumentObj = XDocument.Parse(APIResultSet);
                var Query = from Q in XDocumentObj.Descendants("current_condition")
                            select new WeatherEntity
                            {
                                ObservationTime = (string)Q.Element("observation_time"),
                                Temperature = (string)Q.Element("temp_C"),
                                WeatherIconUrl = (string)Q.Element("weatherIconUrl"),
                                Humidity = (string)Q.Element("humidity"),
                                WindSpeedKmph = (string)Q.Element("windspeedKmph")
                            };

                return  Query.ToList<WeatherEntity>()[0];
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message); 
            }
        }

        /// <summary>
        /// Get Five Days Weather Data including Current Date
        /// </summary>
        /// <param name="APIResultSet">Specify the Result Object which data come from Weather API</param>
        /// <returns>List</returns>
        public static List<WeatherEntity> GetWeatherData(String APIResultSet)
        {
            try
            {
                XDocument XDocumentObj = XDocument.Parse(APIResultSet);
                var Query = from Q in XDocumentObj.Descendants("weather")
                            select new WeatherEntity
                            {
                                Date = (string)Q.Element("date"),
                                TemperatureMaxC = (string)Q.Element("tempMaxC"),
                                TemperatureMinC = (string)Q.Element("tempMinC"),
                                WeatherIconUrl = (string)Q.Element("weatherIconUrl"),
                            };

                return Query.ToList<WeatherEntity>();
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message); 
            }
        }

        #endregion
    }
}

We parse the XMLs in two sections. One is the Current Condition of weather, and another is the information of present day along with the next four days.

Step 9
In MainPage Constructor,we have to check the if there are network connection available or not,it is look like this
public MainPage()
        {
            InitializeComponent();

            try
            {
                // Is there network connection available
                if (!System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable())
                {
                    MessageBox.Show("There is no network connection available!");
                    return;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message); 
            }
        }

Step 10
Add a Following Code on Go Button Click event,it is look like this
private void btnGo_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                WebClient WCObj = new WebClient();
                WCObj.DownloadStringCompleted += new DownloadStringCompletedEventHandler(WCObj_DownloadStringCompleted);
                WCObj.DownloadStringAsync(new Uri("http://free.worldweatheronline.com/feed/weather.ashx?key=bed6524371124406111310&q=" + txtSearchCity.Text.Trim() + "&num_of_days=5&format=xml"));
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message); 
            }
        }

 WebClient Class to load XML data asynchronously from Weather Online Server.

Step 11
Add a following code on DownloadStringCompleted event,it is look like this
void WCObj_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            try
            {
                if (e.Result != null || e.Error == null)
                {

                    // Bind Current Weather Data
                    GCurrentWeather.DataContext = Weather.GetCurrentWeatherData(e.Result);

                    // Visible Grid
                    GWeather.Visibility = System.Windows.Visibility.Visible;

                    // Bind Five Days Weather Data Info
                    LstWeather.DataContext = Weather.GetWeatherData(e.Result);
                }
                else
                {
                    MessageBox.Show("Cannot load Weather Forecast!");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message); 
            }
        }


Run the Application.

Output



Click on Image for better View

Full MainPage Code Behind Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;

namespace SolWeatherApp
{
    public partial class MainPage : PhoneApplicationPage
    {
        public MainPage()
        {
            InitializeComponent();

            try
            {
                // Is there network connection available
                if (!System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable())
                {
                    MessageBox.Show("There is no network connection available!");
                    return;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message); 
            }
        }

        private void btnGo_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                WebClient WCObj = new WebClient();
                WCObj.DownloadStringCompleted += new DownloadStringCompletedEventHandler(WCObj_DownloadStringCompleted);
                WCObj.DownloadStringAsync(new Uri("http://free.worldweatheronline.com/feed/weather.ashx?key=bed6524371124406111310&q=" + txtSearchCity.Text.Trim() + "&num_of_days=5&format=xml"));
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message); 
            }
        }

        void WCObj_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            try
            {
                if (e.Result != null || e.Error == null)
                {

                    // Bind Current Weather Data
                    GCurrentWeather.DataContext = Weather.GetCurrentWeatherData(e.Result);

                    // Visible Grid
                    GWeather.Visibility = System.Windows.Visibility.Visible;

                    // Bind Five Days Weather Data Info
                    LstWeather.DataContext = Weather.GetWeatherData(e.Result);
                }
                else
                {
                    MessageBox.Show("Cannot load Weather Forecast!");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message); 
            }
        }
    }
}

Download
Download Source Code

I was created a Google Weather application before three month ago but unfortunately Google Corporation stop this service.I hope you like this example.  

No comments:

Post a Comment