This week post focuses a creating a small blog viewer app as an excuse to learn some new WinRT skills:
I – Retrieving blog posts data
I naturally chose our Cloud and Mobile devblog as candidate for this app. It is hosted on typepad, which expose a REST/json API in order to access the blog post data. I didn’t investigate much all the capabilities offered by the API: it has a convenient REST call that will return the 50 latest posts on the blog. Here is the C# code that will get back those posts in my custom collection object. I was using the RestSharp API to perform the call easily (a special version of RestSharp is required to be compatible with WinRT):
// performs REST request to retrieve the 50 most recent posts
// http://api.typepad.com/blogs/blogId/post-assets/@published/@recent.js
public async static Task<AdnBlogPostCollection> GetBlogPosts(
string blogDisplayName,
string blogId)
{
string baseUrl =
"http://api.typepad.com/blogs/"
+ blogId +
"/post-assets/@published/";
RestClient client = new RestClient(baseUrl);
RestRequest request = new RestRequest
{
Resource = "@recent.js",
Method = Method.GET,
};
IRestResponse response =
await client.ExecuteAsync(request);
// removes "callback{ ... }" component around reply
string content = response.Content.Substring(
9, response.Content.Length-17);
// uses Linq to JSON
JObject result = JObject.Parse(content);
// 50 posts entries
IList<JToken> entries =
result["entries"].Children().ToList();
return new AdnBlogPostCollection(blogDisplayName, entries);
}
II – Displaying Results
We then place the results in a data-binded listview. Each item contains the avatar of the author of that post, then title and author name. Here is the XAML:
<ListView
Name="listView"
HorizontalAlignment="Stretch"
Grid.Row="1"
VerticalAlignment="Stretch"
ItemsSource="{Binding}" Margin="150, 0, 0,0">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Name="Image" Width="50" Margin="3">
<Image.Source>
<BitmapImage
UriSource="{Binding author.avatarLink.url}"/>
</Image.Source>
</Image>
<StackPanel Orientation="Vertical">
<TextBlock
FontWeight="SemiBold"
Text="{Binding DecodedTitle}"
TextWrapping="Wrap" Width="500"/>
</StackPanel>
<TextBlock
Text="by " TextWrapping="Wrap" Width="20"/>
<TextBlock
Text="{Binding author.displayName}"
TextWrapping="Wrap"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The code behind is very straightforward, just need to set the data source for our listview:
listView.DataContext =
new ObservableCollection<object>(
_postCollection.Items);
One of the highlight here is that the UI can display a picture by directly data-bind the url of the image from the web, which I found pretty cool:
<Image Name="Image" Width="50" Margin="3">
<Image.Source>
<BitmapImage UriSource="{Binding author.avatarLink.url}"/>
</Image.Source>
</Image>
-
-
Another way to get this done is programmatically, here is how it’s done in the post detail page. In that case no data-binding in XAML but just the declaration of the Image place holder:
<Image Grid.Column="1" Width="150" Name="Image" Margin="3"/>
Image.Source = new BitmapImage(
new Uri(_currentPost.author.avatarLink.url, UriKind.Absolute));
-
III – Saving the App state
In order to save WinRT Apps state when they get suspended, you will have to use the LoadState/SaveState of your Page. A Dictionary allows you to easily save <key, Object> pairs to restore them later. One important restriction however is that all you save there has to be serializable, otherwise you may hit a mysterious SuspensionManagerException when your app get suspended by the OS. An easy way to achieve this is to serialize it yourself to a json string. I used for that the Json.Net library which provides very convenient way to achieve that:
protected async override void LoadState(
Object navigationParameter,
Dictionary<String, Object> pageState)
{
// Allow saved page state to override the initial item to display
if (pageState != null && pageState.ContainsKey("Content"))
{
_postCollection =
JsonConvert.DeserializeObject<AdnBlogPostCollection>(
pageState["Content"] as string);
}
else
{
// Initial page loading code ...
}
// rest of your code...
}
protected override void SaveState(
Dictionary<String, Object> pageState)
{
pageState["Content"] =
JsonConvert.SerializeObject(_postCollection);
}
IV – Sending Tile Notifications
The last thing I wanted to play with was sending tile notifications, so I could update my App tile content. Basic tile update is easy and you can achieve that using the NotificationsExtensions library provided by Microsoft Tile & Badge Sample:
private void UpdateTileContent()
{
string stringContent =
_currentPost.DecodedTitle +
" by " +
_currentPost.author.displayName;
// create the wide template
ITileWideText03 tileContent =
TileContentFactory.CreateTileWideText03();
tileContent.TextHeadingWrap.Text = stringContent;
// Users can resize tiles to square or wide.
// Apps can choose to include only square assets
// (meaning the app's tile can never be wide), or
// include both wide and square assets
// (the user can resize the tile to square or wide).
// Apps cannot include only wide assets.
// Apps that support being wide should include
// square tile notifications since users
// determine the size of the tile.
// create the square template and attach it to the wide template
ITileSquareText04 squareContent =
TileContentFactory.CreateTileSquareText04();
squareContent.TextBodyWrap.Text = stringContent;
tileContent.SquareContent = squareContent;
// send the notification
TileUpdateManager.CreateTileUpdaterForApplication().Update(
tileContent.CreateNotification());
}
My tile will contain the current blog post title the App is displaying:
Full source code for this sample is available here on Github.
Comments