Entries:
Comments:
Posts:

Loading User Information from Channel 9

Something went wrong getting user information from Channel 9

Latest Achievement:

Loading User Information from MSDN

Something went wrong getting user information from MSDN

Visual Studio Achievements

Latest Achievement:

Loading Visual Studio Achievements

Something went wrong getting the Visual Studio Achievements

Currency Converter for Windows Phone 7

The purpose of this article is to show how you can make your very own, very simple Currency Converter application for Windows Phone 7, using Bing to make all the hard exchanging work!

conversion_splashIntroduction

Microsoft has done an absolutely amazing job with the Windows Phone 7, giving each and every one of us all of the necessary tools to make our applications blend nicely on it; and the best part—the tools are, and will always be, free!!! J

Using Bing for the currency exchange

First let's look at what happens when I open up Bing on my browser, and enter a search query like “1 US Dollar in Euros”:

image

As you can see, Bing correctly understood my query, and knew that I was looking for an exchange rate. Then MSN Money made the exchange and presented the result.

Also, notice that the address displays as:

http://www.bing.com/search?q=1+US+Dollar+in+Euros&go=&form=QBRE&qs=n&sk=&sc=1-20

OK, but how can we use this to feed the WP7 application? Call the Internet Explorer Developer Tools (just press F12 on your IE8+) and use the “Select element by click” option (Ctrl + B) to select the result on the page and see its HTML code. The result will look just like this:

image

Now we know how to build the Bing currency exchange search query (using “http://www.bing.com/search?q={VALUE}+{SOURCE_CURRENCY}+in+{DESTINATION_CURRENCY}&go=&form=QBRE&qs=n&sk=&sc=1-20”) and also how to find the results on the returned HTML (search the “<span class="sc_bigLine">RESULT</span>”).

The final task is selecting that span tag on the full HTML and then extracting the converted amount; for this task, I'll be using the following Regular Expression (using System.Text.RegularExpressions):

C#

static Regex _resultRegex =   new Regex("<span class=\"sc_bigLine\">.*? = (?<value>[0-9.,]+).*?</span>");

 

This expression searches the HTML code for a span with class “sc_bigLine” and inner content matching something like the above example: “1 USD = 0.71270 EUR”.

The expression also allows me to extract the number after the “=” sign by using Groups[“value"].value property.

MVVM is our friend!

I'll start by quoting the Wikipedia:

The Model View ViewModel (MVVM) is an architectural pattern used in software engineering (…) is targeted at modern UI development platforms (Windows Presentation Foundation and Silverlight) in which there is a User Experience (UX) developer who has different requirements than a more “traditional” developer (i.e. oriented toward business logic and back end development).

Basically, the point is to clearly separate the user interface from all the business logic and data that our application will use!

We can summarize the MVVM pattern with this schema:

image

The View is the basic XAML for the user interface (although sometimes it can have a C# file attached to it) that will use Data Binding to read and change properties on the ViewModel, and Actions to invoke the methods.

The ViewModel is the abstraction of the View and will do all the work for binding the View to the Model, with the necessary data conversion.

The Model can represent the actual object model instance in a known state, or just a data access layer.

There is one basic rule in MVVM: don't look up! The Model has no knowledge of either the ViewModel or the View, and the ViewModel has no knowledge of the View.

This brings a new challenge on how to make the three components talk between themselves, and that's where notifications come along!

We use notifications to communicate changes from a lower component to an upper one; when the upper component gets notified, it will then query the lower for what changed and act accordingly to the new state!

You can read more about MVVM throughout the internet, but there is an article by Shawn Wildermuth that's one of the best I've seen; you can read it here: http://msdn.microsoft.com/enus/magazine/dd458800.aspx.

The Model

We will start at the very bottom (a.k.a. the Model), and as such I've created the following Interfaces to support our Data Model:

imageimage

C#

using System; public interface ICurrencyExchangeService{    ICurrency[] Currencies { get; }    void ExchangeCurrency(        double amount,         ICurrency fromCurrency,         ICurrency toCurrency,         Action<ICurrencyExchangeResult> callback);} public interface ICurrency{    string Name { get; }} public interface ICurrencyExchangeResult{    Exception Error { get; }    string ExchangedCurrency { get; }    double ExchangedAmount { get; }}

 

From these three interfaces, we will extend our Bing Currency Exchange provider:

The abstract CurrencyExchangeServiceBase class implements the ICurrencyExchangeService.ExchangeCurrency method to do all the asynchronous work required to request data from a webserver and retrieve the resulting HTML; to achieve its goal, the CurrencyExchangeServiceBase has two abstract methods that must be implemented: CreateRequestUrl, to get the request url that will be passed to the WebRequest, and GetResultFromResponseContent, to parse the received HTML and return the exchanged value.

We then extend the BingCurrencyExchangeService from CurrencyExchangeServiceBase, implementing the CreateRequestUrl and GetResultFromResponseContent required methods and the ICurrencyExchangeService.Currencies property including all currencies supported by this service instance.

We have also a basic ICurrency interface implementation class called BingCurrency.

This is the CurrencyExchangeServiceBase abstract class implementation:

image

C#

public abstract class CurrencyExchangeServiceBase : ICurrencyExchangeService{   public abstract ICurrency[] Currencies { get; }   protected abstract string CreateRequestUrl(        double amount,         ICurrency fromCurrency,         ICurrency toCurrency);   protected abstract double         GetResultFromResponseContent(string responseContent);   public void ExchangeCurrency(        double amount,         ICurrency fromCurrency,         ICurrency toCurrency,         Action<ICurrencyExchangeResult> callback)   {      var url = CreateRequestUrl(amount, fromCurrency, toCurrency);      var request = HttpWebRequest.Create(url);      request.BeginGetResponse(ar =>       {         try         {            var response = (HttpWebResponse)request.EndGetResponse(ar);            if (response.StatusCode == HttpStatusCode.OK)            {               string responseContent;               using (var streamReader =                   new StreamReader(response.GetResponseStream()))               {                  responseContent = streamReader.ReadToEnd();               }               var exchangedCurrency =                   GetResultFromResponseContent(responseContent);               callback(                  new CurrencyExchangeResult(                     toCurrency.Name,                      exchangedCurrency));            }            else            {               throw new Exception(                string.Format("Http Error: ({0}) {1}",                  response.StatusCode,                  response.StatusDescription));            }         }         catch (Exception ex)         {            callback(new CurrencyExchangeResult(ex));         }      }, null);   }}

 

As I said before, this is an abstract class that requires any inheritor to implement the Currencies property as well as the CreateRequestUrl and GetResultFromResponseContent functions—and that's exactly what the BingCurrencyExchangeService class does:

C#

public class BingCurrencyExchangeService : CurrencyExchangeServiceBase{   private static Regex _resultRegex =       new Regex("<span class=\"sc_bigLine\">.*? = (?<value>[0-9.,]+).*?</span>");   private static ICurrency[] _currencies = new ICurrency[] {       new BingCurrency("Euro"),      new BingCurrency("US Dollar")      //all available currencies will go here!   };   #endregion   public override ICurrency[] Currencies   {      get      {         return _currencies;      }   }   protected override string CreateRequestUrl(double amount, ICurrency fromCurrency, ICurrency toCurrency)   {      return string.Format(         @"http://www.bing.com/search?q={0}+{1}+in+{2}&scope=web&mkt=en-US&FORM=W0LH",         amount,         fromCurrency.Name.Replace(" ", "+"),         toCurrency.Name.Replace(" ", "+"));   }   protected override double GetResultFromResponseContent(string responseContent)   {      var match = _resultRegex.Match(responseContent);      if (match.Success)         return double.Parse(            match.Groups["value"].Value,             CultureInfo.InvariantCulture);      else         throw new Exception("Conversion not returned!");   }}

 

As you can see here, the BingCurrencyExchangeService class knows how to build the Bing search url if given the currencies and the value of exchange, and also how to get the converted value out of the response HTML code (notice the usage of our regular expression).

The ViewModel

The ViewModel has a basic inheritance requirement: using INotifyPropertyChanged to notify the user interface of property value changes.

Our MainViewModel class will have to expose three base data properties for the user interface controls: FromCurrency, ToCurrency, and Amount.

All assembled, this is how the ViewModel looks:

C#

public class MainViewModel : INotifyPropertyChanged{   private ICurrencyExchangeService _currencyExchangeService;   private double _amount;   private ICurrency _fromCurrency;   private ICurrency _toCurrency;   public ICurrencyExchangeService CurrencyExchangeService   {      get      {         return _currencyExchangeService;      }      set      {         if (_currencyExchangeService == value)            return;         _currencyExchangeService = value;         _fromCurrency = Currencies.FirstOrDefault(x => x.Name == "US Dollar") ?? Currencies[0];         _toCurrency = Currencies.FirstOrDefault(x => x.Name == "Euro") ?? Currencies[1];         RaisePropertyChanged("CurrencyExchangeService");         RaisePropertyChanged("Currencies");      }   }   public ICurrency[] Currencies   {      get      {         return _currencyExchangeService.Currencies;      }   }   public string Amount   {      get      {         return _amount.ToString("0.00");      }      set      {         double amount;         if (double.TryParse(value, out amount))         {            if (_amount == amount)               return;            _amount = amount;            RaisePropertyChanged("Amount");         }         else            throw new Exception("Please enter a valid Amount");      }   }   public ICurrency FromCurrency   {      get      {         return _fromCurrency;      }      set      {         if (_fromCurrency == value)            return;         _fromCurrency = value;         RaisePropertyChanged("FromCurrency");      }   }   public ICurrency ToCurrency   {      get      {         return _toCurrency;      }      set      {         if (_toCurrency == value)            return;         _toCurrency = value;         RaisePropertyChanged("ToCurrency");      }   }   public MainViewModel()   {      CurrencyExchangeService = new BingCurrencyExchangeService();      Amount = "100";   }   public event PropertyChangedEventHandler PropertyChanged;   private void RaisePropertyChanged(string propertyName)   {      if (PropertyChanged != null)         PropertyChanged(this, new PropertyChangedEventArgs(propertyName));   }}

 

In order to allow the user to change the FromCurrency and ToCurrency properties, we need to list the available ones; as such, we added a Currencies property to return the ICurrency[] Currencies property of the Model instance.

On the MainViewModel constructor, set the CurrencyExchangeService property to a new BingCurrencyExchangeService instance, making it retrieve “Euro” and “US Dollar” (if available; if not, get the 1st and 2nd one instead) as the two default exchange currencies, and then set the Amount property to an initial value of “100.”

The PropertyChanged event is a basic implementation of the INotifyPropertyChanged interface, with a helper method called RaisePropertyChanged used to invoke the event.

Now we need to add functionality to request a currency exchange operation and show the results on the user interface:

C#

public class MainViewModel : INotifyPropertyChanged{    //remaining code...    private ICurrencyExchangeResult _result;    public ICurrencyExchangeResult Result    {        get        {            return _result;        }        protected set        {            if (_result == value)                return;            _result = value;            RaisePropertyChanged("Result");            RaisePropertyChanged("ExchangedCurrency");            RaisePropertyChanged("ExchangedAmount");        }    }    public string ExchangedCurrency    {        get        {            if (_result == null)                return string.Empty;            return _result.ExchangedCurrency;        }    }    public string ExchangedAmount    {        get        {            if (_result == null)                return string.Empty;            return _result.ExchangedAmount.ToString("N2");        }    }    public void ExchangeCurrency()    {        _currencyExchangeService.ExchangeCurrency(_amount, _fromCurrency, _toCurrency, CurrencyExchanged);    }    private void CurrencyExchanged(ICurrencyExchangeResult result)    {        System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() =>        {            Result = result;        });    }}

 

The ExchangeCurrency method will be used to request a currency exchange operation on the Model instance, including the entered data. When the operation ends, the CurrencyExchanged method will be invoked and we will then get an ICurrencyExchangeResult instance with the results; this method will be asynchronously called on another thread, so we will need get the current Dispatcher and use it to invoke the changes to the MainViewModel.Result property (so that they are made on the interface thread).

As the Result property gets changed, it will also make property changed notifications to the ExchangedCurrency and ExchangedAmount properties, allowing the user interface to show the returned values.

The View

The View that will support our application is really quite simple!

The basic requirements are two ListPicker controls (these are implemented on the Silverlight Toolkit): one for each Currency (the MainViewModel FromCurrency and ToCurrency properties) and a TextBox for the Amount.

We also need two more TextAreas to show the currency exchange results (one for the ExchangedCurrency property and the other for the ExchangedAmount property, both from our MainViewModel).

Using the current MainPage.xaml, start by adding a reference to the Silverlight for Windows Phone Toolkit, like so:

XAML

<phone:PhoneApplicationPagexmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"&lt;!--remaining code... -->

 

Then, I'll change the default ContentPanel control from a Grid to a StackPanel, and add the required controls to edit the Currencies and the entry Value:

XAML

<StackPanel x:Name="ContentPanel" Grid.Row="1" Margin="12,0">   <TextBlock       Margin="12,0,0,-5"       Style="{StaticResource PhoneTextSubtleStyle}">      Amount   </TextBlock>   <TextBox       InputScope="TelephoneNumber"       Text="{Binding Amount, Mode=TwoWay, ValidatesOnExceptions=True, NotifyOnValidationError=True}" />   <TextBlock       Margin="12,10,0,-5"       Style="{StaticResource PhoneTextSubtleStyle}">         From   </TextBlock>   <toolkit:ListPicker       ItemsSource="{Binding Currencies}"       SelectedItem="{Binding FromCurrency, Mode=TwoWay}"       FullModeHeader="FROM CURRENCY"       Style="{StaticResource CurrencyListPicker}" />   <TextBlock       Margin="12,10,0,-5"       Style="{StaticResource PhoneTextSubtleStyle}">      To   </TextBlock>   <toolkit:ListPicker       ItemsSource="{Binding Currencies}"       SelectedItem="{Binding ToCurrency, Mode=TwoWay}"       FullModeHeader="TO CURRENCY"       Style="{StaticResource CurrencyListPicker}" />   <StackPanel>      <TextBlock          Style="{StaticResource PhoneTextGroupHeaderStyle}"          Text="{Binding ExchangedCurrency}" />      <TextBlock          Margin="25, 0, 0, 0"          Style="{StaticResource PhoneTextTitle1Style}"          Text="{Binding ExchangedAmount}" />   </StackPanel></StackPanel>

 

Here's how it looks right now:

image

Notice the CurrencyListPicker style applied to the two ListPicker controls on the code above? Here it is:

XAML

<phone:PhoneApplicationPage.Resources>   <Style x:Key="CurrencyListPicker" TargetType="toolkit:ListPicker">      <Setter          Property="DisplayMemberPath"          Value="Name" />      <Setter          Property="CacheMode"          Value="BitmapCache" />      <Setter Property="FullModeItemTemplate">         <Setter.Value>            <DataTemplate>               <StackPanel                      Orientation="Horizontal"                      Margin="16 21 0 20">                  <TextBlock                      Text="{Binding Name}"                      FontSize="43"                      FontFamily="{StaticResource PhoneFontFamilyLight}"/>               </StackPanel>            </DataTemplate>         </Setter.Value>      </Setter>   </Style></phone:PhoneApplicationPage.Resources>

 

This style sets the initial values of three properties on the ListPickers: the DisplayMemberPath (it will be binded to the ICurrency.Name property), the CacheMode (for optimization only), and, most importantly, the FullModeItemTemplate, which indicates how to show each item when the ListPicker window pops up.

The next step will be adding the “Exchange” button to the bottom ApplicationBar, like so:

XAML

<phone:PhoneApplicationPage.ApplicationBar>   <shell:ApplicationBar       IsVisible="True"       IsMenuEnabled="False">      <shell:ApplicationBarIconButton          IconUri="/Images/appbar.money.usd.png"          Text="Exchange"          Click="ExchangeIconButton_Click" />   </shell:ApplicationBar></phone:PhoneApplicationPage.ApplicationBar> 

 

Remember to create an Images folder in your project and copy the required “appbar.money.usd.png” image to it (you can find this and other ApplicationBar icons in your “%ProgramFiles%\Microsoft SDKs\Windows Phone\v7.0\Icons\dark”); then, set its “Build” and “Copy to Output Directory” properties to “Content” and “Copy always”, respectively.

On the MainPage.xaml.cs, we'll add the ExchangeIconButton_Click() method:

C#

private void ExchangeIconButton_Click(object sender, EventArgs e){   var viewModel = DataContext as MainViewModel;   if (viewModel == null)      return;   Focus();   Dispatcher.BeginInvoke(() =>   {      if (!NetworkInterface.GetIsNetworkAvailable())      {         MessageBox.Show(            "No network connection found!",             "Error",             MessageBoxButton.OK);         return;      }      viewModel.ExchangeCurrency();   });}

 

This method will check for a valid MainViewModel set on the DataContext, remove the Focus from any TextBox (thus hiding the on-screen keyboard), check if there is a valid network connection, and then call the MainViewModel.ExchangeCurrency() method.

Tombstoning

The final piece to developing this into the perfect Windows Phone 7 application is making it “Tombstoning” aware!

Since WP7 doesn't allow multitasking, every time an application is deactivated or closed you should save its state and then restore it when the application is reactivated or reopened; this process is called “Tombstoning.”

To do this, we use the System.Runtime.Serialization classes, namely, the DataMemberAttribute to mark all the properties of the MainViewModel we want to save (FromCurrency, ToCurrency, and Amount), and the IgnoreDataMemberAttribute to mark the ones we don't (CurrencyExchangeService, Currencies, Result, ExchangedCurrency, and ExchangedAmount).

We can't (or at least, shouldn't!) directly save the state of the FromCurrency and ToCurrency properties because they have complex values (rather than a base type like Int or String), so we mark these with the IgnoreDataMemberAttribute and add two new properties, one for each, that will get/set the relative index of the Currencies array:

C#

[DataMember] public int FromCurrencyIndex{    get    {        return Array.IndexOf(Currencies, FromCurrency);    }    set    {        FromCurrency = Currencies[value];    }}[DataMember] public int ToCurrencyIndex{    get    {        return Array.IndexOf(Currencies, ToCurrency);    }    set    {        ToCurrency = Currencies[value];    }}

 

Now add the methods to Load and Save the state of the MainViewModel instance; since the Save method has to be called on the App.xaml.cs Application_Deactivated() and Application_Closing() events, the best way is to make our View Model a singleton. To do this, add the following code to the MainViewModel class:

C#

[IgnoreDataMember] private const string SettingFileName = "mainviewmodel.dat"; public static MainViewModel Instance { get; protected set; } static MainViewModel(){    Instance = Load();} public static MainViewModel Load(){    return StorageHelper.LoadContract<MainViewModel>(SettingFileName, true);} public void Save(){    StorageHelper.SaveContract(SettingFileName, this, true);}

 

The StorageHelper class you see here is just a helper used to serialize and deserialize a file on the application's IsolatedStorage.

Now all we have to do is change the MainPage.xaml.cs constructor so it uses the singleton instead of creating a new MainViewModel instance:

C#

public MainPage(){    InitializeComponent();    this.DataContext = MainViewModel.Instance;}

 

Finally, invoke the Save method on the two required events of the App.xaml.cs file:

C#

private void Application_Deactivated(object sender, DeactivatedEventArgs e){    MainViewModel.Instance.Save();} private void Application_Closing(object sender, ClosingEventArgs e){    MainViewModel.Instance.Save();}

 

And that is it! To test the application, open it, press the windows key so that the Windows Phone main screen appears, wait a couple of seconds, and press the back key to return to the application: you will see a “resuming” message appear when the application state restores!

The application can now be Tombstoned anytime, and when it gets opened again, it will appear as if it never closed!

Conclusion

As you see here, you can build simple applications for Windows Phone 7 by using basic MVVM architecture, and still have time to go out and have a coffee with your friends!

Remember: If you want to try this out, the download link for the source code is at the top of the article!

The sample code uses the BingCurrencyExchangeService, but it also has a second provider for MSN Money, the MsnMoneyCurrencyExchangeService, which you can check out!

About The Author

Pedro Lamas is a Portuguese .Net Senior Developer on Microsoft's Partner DevScope, where he works with all the cool stuff that Microsoft .Net has to offer its developers!

He's also one of the administrators of PocketPT.net, the largest Windows Phone Portuguese community, where his contribution is mostly visible on support for Windows Phone developers, and as a speaker for Windows Phone Development in Microsoft Portugal Events.

You can read his blog or contact him via twitter!

Tags:

Follow the Discussion

Remove this comment

Remove this thread

close

Comments Closed

Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation, please create a new thread in our Forums,
or Contact Us and let us know.