Building the Developer.Com Windows 8 App

WEBINAR: On-demand webcast

How to Boost Database Development Productivity on Linux, Docker, and Kubernetes with Microsoft SQL Server 2017 REGISTER >

I was asked to build a Windows Store Application for the Developer.com Network. This was to be a reader app running on Windows 8. The request was for the first version to provide you (the reader) with a list of posts with summaries, that when selected will allow you to read the full article. The first version of this Win8 application would be limited to reading from just a few of the Developer.com Network sites; CodeGuru.com, Developer.com, DevX.com, HTMLGoodies.com and PHPBuilder.com.

I started this assignment about a week ago. The Windows 8 platform provides quite a few tools that make life easier for us. Today is launch day and the application is built and has been submitted to the Widnows 8 App Store. You should have access to it within a few days. In the meantime, I'll share with you what I built, including the code!

First things first, we need to be able to pull down the rss feeds from the 5 sites. The first thing that comes to mind may be to use the WebClient, pull down the XML and use LINQ to XML to parse out the items. While this approach would in fact work; however, we can take advantage of the SyndicationClient from the Windows.UI.Xaml.Media namespace. The SyndicationClient allows you to request an RSS feed by URL and the client itself will take care of the headache of parsing out the XML elements. To get started, I've created two helper classes Feed and FeedItem as listed below:

class Feed
    {
        public string Title { get; set; }
        public string URL { get; set; }
        public string ItemIcon { get; set; }
        public string ItemBackground { get; set; }
        public string ItemTextColor { get; set; }
    }
 
    class FeedItem
    {
        public string Title { get; set; }
        public string URL { get; set; }
        public string ID { get; set; }
        public string Description { get; set; }
        public DateTime PublicationDate { get; set; }
        public string Author { get; set; }
 
        public string Site { get; set; }
        public string ItemIcon { get; set; }
        public string ItemBackground { get; set; }
        public string ItemTextColor { get; set; }
    }
 
 

The feed class is used to define an RSS feed we want to pull as well as other info we need later for the UI including the site icon, and colors.  The feed item is used to capture information about individual items pulled back from the feeds.  The FeedItem itself will be used later for binding to the UI in an ObservableCollection<FeedItem>.  

Using the feed class, we can create the required info for the developer.com site as shown below:

 Feed f = new Feed()
 {
   Title = "Developer.com",
   URL = "http://www.developer.com/rss.xml",
   ItemIcon = "Assets/logo150x150.png",
   ItemBackground = "#FF0021B5",
   ItemTextColor = "#FFFFFFFF"
 };

Next we can make use of the SyndicationClient and pull back a complete list of items for the feed using the following method.  This method makes use of async/await programming styles which are quite different from traditional styles.  If you are not familiar with this technique check out the CodeGuru on “Creating and Managing Asynchronous Operations in Windows Runtime (WinRT)”  The purpose for using this technique is to minimize the impact on the user interface thread.

        private async Task<List<FeedItem>> UpdateFeed(Feed f)
        {
            List<FeedItem> items = new List<FeedItem>();
            SyndicationClient client = new SyndicationClient();
            var feed = await client.RetrieveFeedAsync(new Uri(f.URL));
            foreach (var item in feed.Items)
            {
                    FeedItem newitem = new FeedItem();
                    newitem.ID = item.Id;
                    newitem.PublicationDate = item.PublishedDate.ToLocalTime().DateTime;
                    if (item.Id != null && item.Id.Trim().Length > 0)
                    {
                        newitem.URL = item.Id;
                    }
                    else
                    {
                        //Grab the Link
                        newitem.URL = item.Links[0].NodeValue;
                    }
                    newitem.Title = item.Title.Text;
                    newitem.Description = StripHTML(item.Summary.Text);
                    newitem.Author = String.Join(", ", item.Authors.Select(x => x.Name).ToArray());
                    newitem.ItemIcon = f.ItemIcon;
                    newitem.ItemBackground = f.ItemBackground;
                    newitem.ItemTextColor = f.ItemTextColor;
                    newitem.Site = f.Title;
                    items.Add(newitem);
            }
            return items;
        }

The UpdateFeed method pulls down the RSS feed using the provided information.  From there it pulls out the fields needed and returns a List of FeedItem within a Task.  At the point in which the method returns the UpdateFeed method is still in the process of pulling down data which is why the List of FeedItems is contained within a task.  To get those we would need to do use an await statement as follows.

List<FeedItem> items = await UpdateFeed(f);

For the developer.com network reader app we need to go to the next level and process a list of feeds and come up with a combined list of items.  If we add each of the Feed objects to a list called Feeds we could use the following code snippet to pull down the complete list of items and put them all within a single list.

            List<FeedItem> TempFeedItems = new List<FeedItem>();
            foreach (var ff in Feeds)
            {
                Task<List<FeedItem>> itemtask = UpdateFeed(ff);
                foreach (var item in await itemtask)
                {
                    TempFeedItems.Add(item);
                }
            }
 

This code will loop through the feeds, call the UpdateFeed method on each and produce a combined list called TempFeedItems.  This list will contain all of the items; however, we would want to have all of the items sorted by publish date descending.  To accomplish this we would want to add the following snippet.

            foreach (var item in TempFeedItems.OrderByDescending(i => i.PublicationDate))
            {
                CombinedFeed.Add(item);
            }

The CombinedFeed mentioned above should be an ObservableCollection<FeedItem> so we can use this final list for binding to the UI.

At this point, we are ready to bind the observable collection to the UI elements.  The binding for the CombinedFeed to the UI is fairly normal, create the Resource on the page for the itemsViewSource as shown below:

<CollectionViewSource   x:Name="itemsViewSource"  Source="{Binding Items}"  />

Next, attach the CombinedFeed from above with the itemViewSource.

this.DefaultViewModel["Items"] = CombinedFeed;

For this app we are using a GridView to display the feed items in a horizontal scrolling pattern like other metro style apps.

        <GridView
            x:Name="itemGridView"
            AutomationProperties.AutomationId="ItemsGridView"
            AutomationProperties.Name="Items"
            TabIndex="1"
            Grid.RowSpan="2"
            Padding="116,136,116,46"
            ItemsSource="{Binding Source={StaticResource itemsViewSource}}"
            ItemTemplate="{StaticResource FeedItemTemplate}"
            IsSwipeEnabled="false"
            SelectionMode="None"
            IsItemClickEnabled="True"
            ItemClick="itemGridView_ItemClick"/>

Next we need the data template used to display individual items, which can be somewhat complicated to define the look and feel you are going for.

        <DataTemplate x:Key="FeedItemTemplate">
            <Grid Height="200" Margin="6" Background="{Binding ItemBackground}" Width="400">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="*" />
                </Grid.RowDefinitions>
                <Border Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}" Width="75" Height="75" Grid.Row="0" Grid.Column="0" VerticalAlignment="Top" >
                    <Image Source="{Binding ItemIcon}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}"/>
                </Border>
                <StackPanel Grid.Column="1" VerticalAlignment="Top" Margin="10,0,0,0">
                    <TextBlock Style="{StaticResource TitleTextStyle}" Foreground="{Binding ItemTextColor}">
                        <Run Text="{Binding Title}" />                    
                    </TextBlock>
                    <TextBlock Style="{StaticResource CaptionTextStyle}" Foreground="{Binding ItemTextColor}">
                        <Run Text="Published " />
                        <Run Text="{Binding PublicationDate}" />                        
                    </TextBlock>
                    <TextBlock Text="{Binding Site}" Style="{StaticResource CaptionTextStyle}" TextWrapping="NoWrap"  Foreground="{Binding ItemTextColor}"/>
                </StackPanel>
                
                <TextBlock Text="{Binding Description}" Grid.Row="1" Grid.ColumnSpan="2" Margin="10,10,10,10" Style="{StaticResource BodyTextStyle}"  Foreground="{Binding ItemTextColor}"/>
            </Grid>
        </DataTemplate>

Since going through all of the fine details of data templating is outside of the scope of this article, I'll provide an example of the output generated by this template.

Example of Output 
Example of Output

You may have noticed from the GridView definition above, the itemGridView_ItemClick click handler.  This is essential for allowing the user to click on items and view the full text.  Within the click handler, the GridView provides us with the FeedItem the user clicked on in the e.ClickedItem property.  You will need to cast it back to FeedItem; however, it does provide all of the details we need.  If you want to just send the user to a browser to view the details you could use the following statement.

Windows.System.Launcher.LaunchUriAsync(new Uri(((FeedHandling.FeedItem)e.ClickedItem).URL));

Alternatively you could create a custom page and embed the browser within your app.  If you have access to the full content on the site you may choose to make a secondary call to pull the content.

Conclusion

As you can see from above, the SyndicationClient makes the process of pulling down RSS feeds easy and painless.    Furthermore, combining the techniques of asynchronous programming and XAML data binding you can quickly create a feed reader app to pull down and display one or more feeds and display them in a new way for users.



Related Articles

Downloads

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • As all sorts of data becomes available for storage, analysis and retrieval - so called 'Big Data' - there are potentially huge benefits, but equally huge challenges...
  • The agile organization needs knowledge to act on, quickly and effectively. Though many organizations are clamouring for "Big Data", not nearly as many know what to do with it...
  • Cloud-based integration solutions can be confusing. Adding to the confusion are the multiple ways IT departments can deliver such integration...

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date