
After the post
Introduction to the development of WinRT applications in HTML / JavaScript. From the template to the data application, you already know how to develop an RSS reader for Windows 8 using HTML and JavaScript. It's time to try to do about the same thing, but using XAML / C #. This is the first part, but we will make it beautifully!
Creating an application from a template
Let's start development from the Grid template of the application as well, choosing XAML / C # development
From the
File menu, select
New Project, then
Visual C # , then
Windows Store , in the central part of the
New Project window select a template called the
Grid App (XAML) . Enter the name of the application in the
Name field, for example, MyReader, if necessary, in the
Location field the folder where the application project will be located and click the
OK button.

As a result, we get an application that is almost fully functional in navigation and data display, which displays an example of data.
Let's see how it works by pressing
F5 , the green arrow or selecting
Debug ->
Start Debugging
You can make sure that this is almost a full-featured application:
- click on any single gray tile or group title;
- use the back button on the internal pages of the application;
- put the application in snapped mode.
Return to Visual Studio and stop debugging the application (
Shift + F5 , red square, or select
Debug ->
Stop Debugging from the menu).
Let's look at the main files of our solution:
- * .xaml - markup page application in XAML.
- * .xaml.cs is a code-behind file in the C # page language.
- App.xaml - the initialization of the Windows Store-application object in the XAML language, has no visual presentation and is not an application page.
- App.xaml.cs is the C -code code-behind file for App.xaml. This file handles application-level events, such as launch, activation, including activation by search query, and deactivation of the application. In addition, in App.xaml.cs, you can catch unhandled exceptions and catch navigation errors between pages.
- Common folder , StandardStyles.xaml file - style resource file for graphical controls, is connected in App.xaml and its styles are available in all pages of the application.
- Package.appxmanifest is an application manifest, an XML file, containing a variety of application settings. There is a graphic editor that can be opened by double-clicking on the Package.appxmanifest file name in the Solution Explorer window.
- AssemblyInfo.cs is a configuration file that defines some metadata for the main assembly of the application.
- MyReader_TemporaryKey.pfx is a cryptographic certificate with a private key that signs the application.
- Asset folder, Logo.png, SmallLogo.png, StoreLogo.png files - logos for large and small tiles of an application, as well as an icon for a list of all applications.
- SplashScreen.png - a picture for the screen saver, which is displayed during the application download.
Also in the Common folder, there are also files with common code that is used in the application, in the DataModel folder there is a file with the application data model -
SampleDataSource.cs .
Change data to display
So, the application is already running and it has a sample data source implemented. Therefore, task number one is to replace an example of a data source with a real data source.
We start by removing the default constructor of the SampleDataSource class, in which initialization occurs with static data.
public SampleDataSource()
Next, we use the refactoring capabilities built into Visual Studio and rename SampleDataSource to RSSDataSource, SampleDataGroup to RSSDataGroup, SampleDataItem to RSSDataItem and SampleDataCommon to RSSDataCommon.

To create a holistic picture of the world, you can rename the file SampleDataSource.cs to RSSDataSource.cs.
')
To simplify working with the data class in this example, let's simplify it. To do this, replace the following piece of the class RSSDataSource
private static RSSDataSource _sampleDataSource = new RSSDataSource(); private ObservableCollection<RSSDataGroup> _allGroups = new ObservableCollection<RSSDataGroup>(); public ObservableCollection<RSSDataGroup> AllGroups { get { return this._allGroups; } }
A similar code that simplifies the perception and further development of the example.
public static readonly ObservableCollection<RSSDataGroup> AllGroups = new ObservableCollection<RSSDataGroup>();
Finally, remove the unnecessary local variable _sampleDataSource from the class code.
So, we are prepared to add real data.
We add a simple method that will take an RSS or ATOM data stream and submit it for further display in the application interface.
public static async Task<bool> AddGroupForFeedAsync(string feedUrl) { string clearedContent = String.Empty; if (RSSDataSource.GetGroup(feedUrl) != null) return false; var feed = await new SyndicationClient().RetrieveFeedAsync(new Uri(feedUrl)); var feedGroup = new RSSDataGroup( uniqueId: feedUrl, title: feed.Title != null ? feed.Title.Text : null, subtitle: feed.Subtitle != null ? feed.Subtitle.Text : null, imagePath: feed.ImageUri != null ? feed.ImageUri.ToString() : null, description: null); foreach (var i in feed.Items) { string imagePath = null; if (i.Summary != null) clearedContent = Windows.Data.Html.HtmlUtilities.ConvertToText(i.Summary.Text); else if (i.Content != null) clearedContent = Windows.Data.Html.HtmlUtilities.ConvertToText(i.Content.Text); if (imagePath != null && feedGroup.Image == null) feedGroup.SetImage(imagePath); if (imagePath == null) imagePath = "ms-appx:///Assets/DarkGray.png"; feedGroup.Items.Add(new RSSDataItem( uniqueId: i.Id, title: i.Title.Text, subtitle: null, imagePath: imagePath, description: null, content: clearedContent, @group: feedGroup)); } AllGroups.Add(feedGroup); return true; }
The code is quite simple. Using SyndicationClient, we receive and parse data from RSS / ATOM, after which we create a group and add entries to it. Along the way, we clear the contents of the HTML tags, just to make it look better, and also provide for the addition of a picture, than we will do later.
Do not forget to add the following directive to the using block:
using Windows.Web.Syndication; using System.Threading.Tasks;
To check how it works right away, double-click the GroupedItemsPage.xaml.cs file and go to the LoadState method, which initializes the data and replace the sampleDataGroups data source with RSSDataSource.AllGroups, as well as remove the initialization of sampleDataGroups now unnecessary. Now, the LoadState code consists of one line:
protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState) { this.DefaultViewModel["Groups"] = RSSDataSource.AllGroups; }
Now, to make it work, you need to add some RSS. We use the newly created function AddGroupForFeedAsync and add two lines to the LoadState function:
RSSDataSource.AddGroupForFeedAsync("http://blogs.msdn.com/b/stasus/rss.aspx"); RSSDataSource.AddGroupForFeedAsync("http://www.spugachev.com/feed");
We collect the project and we start.

Hooray - it works!
But somehow everything is not very beautiful ... Well, let's make it beautiful!
Make beautiful
The first thing to start with is pictures in posts and on tiles in a grouped display.
Go back to RSSDataSource.cs and add a magic method that extracts images from RSS posts:
private static string GetImageFromPostContents(SyndicationItem item) { string text2search = ""; if (item.Content != null) text2search += item.Content.Text; if (item.Summary != null) text2search += item.Summary.Text; return Regex.Matches(text2search, @"(?<=<img\s+[^>]*?src=(?<q>['""]))(?<url>.+?)(?=\k<q>)", RegexOptions.IgnoreCase) .Cast<Match>() .Where(m => { Uri url; if (Uri.TryCreate(m.Groups[0].Value, UriKind.Absolute, out url)) { string ext = Path.GetExtension(url.AbsolutePath).ToLower(); if (ext == ".png" || ext == ".jpg" || ext == ".bmp") return true; } return false; }) .Select(m => m.Groups[0].Value) .FirstOrDefault(); }
In the method, we, using regular expressions, try to find pictures (with extensions png, jpg and bmp) in the text of the post or its summary.
Do not forget to add the following directive to the using block:
using System.Text.RegularExpressions; using System.IO;
Now we will add the calls of this method to the stub carefully left in the AddGroupForFeedAsync method. Change
string imagePath = null;
on
string imagePath = GetImageFromPostContents(i);
Reassemble and run the application.

Everything has become much better, but why are all the topics displayed in tiles of the same size? Perhaps you need to do as in the Windows Store!
This is a slightly more difficult task than all that we have done before. But we do not stop in front of difficulties!
In order to implement this functionality, we will have to create our own class, the successor of the GridView. Add a new class file named: VariableSizeGridView.cs to the project. In the new file, add the following directive to the block:
using Windows.UI.Xaml.Controls;
, indicate that the class is inherited from the GridView and override its class method: PrepareContainerForItemOverride. The result should be something like this:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Windows.UI.Xaml.Controls; namespace MyReader { class VariableSizeGridView: GridView { protected override void PrepareContainerForItemOverride(Windows.UI.Xaml.DependencyObject element, object item) { base.PrepareContainerForItemOverride(element, item); } } }
The PrepareContainerForItemOverride method itself will determine the logic by which tiles of different sizes will be displayed in a grouped view. Now you need to prepare the markup in the GroupedItemsPage.xaml file.
First we replace the GridView with our class - local: VariableSizeGridView. Next in the ItemPanelTemplate, we complement the properties of the VariableSizedWrapGrid by specifying the size of the Item and the maximum number of terms and columns so that it will look like this:
<VariableSizedWrapGrid Orientation="Vertical" Margin="0,0,80,0" ItemWidth="200" ItemHeight="125" MaximumRowsOrColumns="9" />
Add your own Item template to the page resources:
<DataTemplate x:Key="CustomItemTemplate"> <Grid HorizontalAlignment="Left"> <Border Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}"> <Image Source="{Binding Image}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}"/> </Border> <StackPanel Background="{StaticResource ListViewItemOverlayBackgroundThemeBrush}" VerticalAlignment="Bottom"> <TextBlock Text="{Binding Title}" Foreground="{StaticResource ListViewItemOverlayForegroundThemeBrush}" Height="90" Margin="15,0,15,0" FontSize="30" /> </StackPanel> </Grid> </DataTemplate>
And specify it as the Item template, instead of the standard in local: VariableSizeGridView ::
<local:VariableSizeGridView x:Name="itemGridView" AutomationProperties.AutomationId="ItemGridView" AutomationProperties.Name="Grouped Items" Grid.RowSpan="2" Padding="116,137,40,46" ItemsSource="{Binding Source={StaticResource groupedItemsViewSource}}" ItemTemplate="{StaticResource CustomItemTemplate}" SelectionMode="None" IsSwipeEnabled="false" IsItemClickEnabled="True" ItemClick="ItemView_ItemClick">
Launch the application.

Looks not very nice. But this is until we add our code with logic to PrepareContainerForItemOverride.
So, add the code:
class VariableSizeGridView: GridView { private int rowVal; private int colVal; protected override void PrepareContainerForItemOverride(Windows.UI.Xaml.DependencyObject element, object item) { RSSDataItem dataItem = item as RSSDataItem; int index = -1; if (dataItem != null) { index = dataItem.Group.Items.IndexOf(dataItem); } if (index == 1) { colVal = 2; rowVal = 4; } else { colVal = 2; rowVal = 2; } if (index == 2) { colVal = 2; rowVal = 4; } if (index == 5) { colVal = 4; rowVal = 4; } VariableSizedWrapGrid.SetRowSpan(element as UIElement, rowVal); VariableSizedWrapGrid.SetColumnSpan(element as UIElement, colVal); base.PrepareContainerForItemOverride(element, item); }
As you can see, we simply indicate with our hands which tiles in order, how to display them.
Run again.

It looks much better, and by implementing the templates for the Item and the logic of the PrepareContainerForItemOverride, we can achieve almost any view within the GridView.
On this I, perhaps, will complete the first part. In the second part, we will continue to do beautifully: we will add live tiles, search contracts and share contracts, and also add RSS feeds to the settings.
UPD : Yes, and we will also make a style for Title, so that it is displayed on human tiles in a grouped display on a human basis, as in the screenshot at the beginning of the article.
The resulting application as a project on SkyDrive (short link):
aka.ms/w8RSSp1Happy New Year!
UPD:Part 2 of the cyclePart of the 3rd cycle