In the first part,
I covered how to get the initial project setup and share the ViewModels and ViewModelLocator between a Windows Phone 8 project and a Windows Store application.
In this post, I'll add a DataService and a Model class that will be used to get the most recent posts from the Windows Phone
blog and display the results.
Adding DataService and Async to Portable Class Library
The purpose of the DataService in the context of this project is to retrieve the RSS feed from the Windows Phone
blog (http://blogs.windows.com/windows_phone/b/wpdev/rss.aspx)
using the async methods available in the 4.5 Framework, and return a collection of our
Headline class object for the UI to handle and display.
Headline Class Model
The Headline class is the object that will be loaded and a collection of these will be built and returned from the data service method.
Create a new folder in the Mvvm.PCL project called "Model" and add a new file called
Headline.cs.
public class Headline
{
public string Title { get; set; }
public string Description { get; set; }
public string Url { get; set; }
public DateTime Published { get; set; }
}
IDataService
In good practice, create an interface for the DataService class. This would allow for taking advantage of dependency injection if you chose to do so.
Add a new interface file to the model folder called IDataService.cs. Here is the interface:
namespace Mvvm.PCL.Model
{
public interface IDataService
{
void GetHeadlines(Action<List<Headline>, Exception> callback);
}
}
The interface defines a single method that accepts a delegate with a collection or List<T> of Headlines and an Exception parameter.
DataService
Next, in the same folder, add the DataService.cs file and implement the interface.
public class DataService : IDataService
{
public void GetHeadlines(Action<List<Headline>, Exception> callback)
{
throw new NotImplementedException();
}
}
HttpWebRequest
Most simple requests for data are done with the WebClient class,
however this class is not available in Portable Class libraries and is really only an abstraction of what must be used and that is the
HttpWebRequest.
Add a new method to the class called MakeAsyncRequest accepting a
URL (string) as a parameter and set the method to return a Task<string>. Within the method,
I'll use the Task.Factory.FromAsync method to call the URL asynchronously returning the
Task<WebRequest> then use a continuation to read the WebResponse.
private static Task<string> MakeAsyncRequest(string url)
{
HttpWebRequest request = WebRequest.CreateHttp(url);
request.Method = "GET";
Task<WebResponse> task = Task.Factory.FromAsync(
request.BeginGetResponse,
(asyncResult) => request.EndGetResponse(asyncResult),
(object)null);
return task.ContinueWith(t => ReadStreamFromResponse(t.Result));
}
private static string ReadStreamFromResponse(WebResponse response)
{
using (Stream responseStream = response.GetResponseStream())
using (StreamReader sr = new StreamReader(responseStream))
{
string strContent = sr.ReadToEnd();
return strContent;
}
}
The GetHeadlines method can now be completed. First add the static URL.
private readonly string uri = "http://blogs.windows.com/windows_phone/b/wpdev/rss.aspx";
Then declare a variable to hold the results of the MakeAsyncRequest method and set the call with the
await keyword so the UI thread is not blocked.
var t = await MakeAsyncRequest(uri);
You will also have to mark the method as async or the compiler will give you an error telling you to do so.
public async void GetHeadlines(Action<List<Headline>, Exception> callback)
{
...
}
The results returned are a string type and there are a couple of options to get it into a nice format to work with. Your first option might be to use
the Silverlight SyndicationFeed class
which is in the System.ServiceModel.Syndication namespace. However, it is not inherently available in the portable classes and you'll need to go searching for it on your dev
machine. Hint (C:\Program Files (x86)\Microsoft SDKs\Silverlight\v4.0\Libraries\Client\System.ServiceModel.Syndication.dll).
I'm choosing to use LINQ and doing LINQ to XML here to get what I need out of the results string and inflate my classes and return it.
Here is the completed method:
public async void GetHeadlines(Action<List<Headline>, Exception> callback)
{
Exception err = null;
List<Headline> results = null;
try
{
var t = await MakeAsyncRequest(uri);
StringReader stringReader = new StringReader(t);
using (var xmlReader = System.Xml.XmlReader.Create(stringReader))
{
var doc = System.Xml.Linq.XDocument.Load(xmlReader);
results = (from e in doc.Element("rss").Element("channel").Elements("item")
select
new Headline()
{
Title = e.Element("title").Value,
Description = e.Element("description").Value,
Published = Convert.ToDateTime(e.Element("pubDate").Value),
Url = e.Element("link").Value
}).ToList();
}
}
catch (Exception ex)
{
err = ex;
}
callback(results, err);
}
That covers all of the code needed in the Portable Class(es) for getting the data, just need to edit the
MainViewModel class constructor to create the DataService class,
implement the new method, and create a Headlines property.
MainViewModel
Add a new property for the headlines to be bound to by the UI.
private List<Model.Headline> _headlines;
public List<Model.Headline> Headlines
{
get { return _headlines; }
set
{
_headlines = value;
RaisePropertyChanged(() => Headlines);
}
}
In the constructor, create an instance of the DataService and execute the method. I did mention earlier that there is an
IDataService
for DI, but for this example a concrete DataService class is created.
public MainViewModel()
{
var service = new DataService();
service.GetHeadlines((headlines, err) => {
if (err != null)
{
System.Diagnostics.Debug.WriteLine(err.ToString());
}
else
{
this.Headlines = headlines;
}
});
}
Adding the UI Elements
Windows Phone
Open the MainPage.xaml page and wrap the previous TextBlock from part 1 in a
StackPanel then add a ListBox. Set the ItemsSource property of the
ListBox
to {Binding Headlines, Mode=TwoWay}, then add a simple template with a
TextBlock to show the title of the story.
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<StackPanel>
<TextBlock Text="{Binding Hello, Mode=TwoWay}" Foreground="White" FontSize="18" />
<ListBox ItemsSource="{Binding Headlines, Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<ListBoxItem>
<TextBlock Text="{Binding Title}" />
</ListBoxItem>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</Grid>
Windows Store
The store app is just as easy. In MainPage.xaml, add a GridView control, set the
ItemsSource to {Binding Headlines, Mode=TwoWay}, but in this case I'll define
an ItemTemplate outside of the control called PCLItemTemplate and display the Title and the Description.
<GridView ItemsSource="{Binding Headlines, Mode=TwoWay}" Grid.Row="1" ItemTemplate="{StaticResource PCLItemTemplate}" />
<Page.Resources>
<DataTemplate x:Key="PCLItemTemplate">
<StackPanel Orientation="Vertical" Width="500" Height="250">
<TextBlock Foreground="White" Text="{Binding Title}" FontSize="18"
HorizontalAlignment="Center" Margin="20,10,20,0" TextTrimming="WordEllipsis"/>
<TextBlock Foreground="White" Text="{Binding Description}"
Style="{StaticResource ItemTextStyle}" HorizontalAlignment="Center" Margin="20,10" TextTrimming="WordEllipsis"/>
</StackPanel>
</DataTemplate>
</Page.Resources>
Summary

Running either apps presents the data in a different context and there is complete control as to the presentation and design choices based on the platform.
If you are looking to create Windows Store apps and/or Windows Phone applications Portable Class Libraries is a great way to leverage code within your multiple
platform target solution. MvvmLight is a choice of mine and many others and fits very well too thanks to others in the community.

Shayne Boyer aka TattooCoder, has been developing Microsoft based solutions for the last 15 years. Currently working as a Solutions Architect focused on Services Oriented Architecture and in his spare time runs the Orlando Windows Phone and Windows 8 User Group. He is a passionate developer and loves to talk about his craft, teach and also learn from others.
- MCSD .NET
- Telerik MVP
- Orlando Windows Phone & Metro User Group Founder (@OrlandoWPUG)
- INETA Speaker
- DZone.com MVB