Understanding development of Windows 8 applications on XAML/С#. Implementing a simple RSS Reader. Part 2.

Stanislav Pavlov

This is the translated copy of the original article written by Stanislav Pavlov for habrahabr.ru.
 
In this article we continue developing a simple RSS Reader. We laid solid foundation in the previous article, “Understanding development of Windows 8 applications on XAML/С#. Implementing a simple RSS Reader. Part 1.” where we’ve created the project, got RSS data and started making it pretty. In this part, we will continue making it pretty and add some more functionality to our reader.
 
Continuing making pretty
 
Continuing making pretty
 
So, now we have pretty tiles of different sizes and if we needed we can “tile” groups in various ways. So, let’s make it. Stas Pavlov’s blog will be done with tiles of different sizes and in Sergey Pugachev’s blog a user will not see such diversity.
 
How to do that? It’s very simple. The logic that determines tiles size is fully implemented in the PrepareContainerForItemOverride function of the VariableSizeGridView class. Thus we can add the corresponding logic there.
 
To identify the groups we will use UniqueID. For a group, it corresponds to the URL in RSS. Let’s add the following code to the PrepareContainerForItemOverride function:
 

int group = -1;

if (dataItem.Group.UniqueId.Contains("stas"))
{
    group = 1;
}

 
And now let’s change function behavior depending on the group it works for by adding the following condition:
 

if (group > 0)
{
    if (index == 2)
    {
        colVal = 2;
        rowVal = 4;
    }

    if (index == 5)
    {
        colVal = 4;
        rowVal = 4;
    }
}

 
Run the application to see how it works.
 
Run Windows 8 the application to see how it works
 
Now let’s set a more complicated mission. What if we need to use absolutely different display templates? It’s also a solvable task. And again we need to implement a custom class that would contain logic but it will be inherited from DataTemplateSelector.
 
So, we add a new class called MyDataTemplateSelector to the solution and indicate that it is inherited from DataTemplateSelector. Add the following directives to the using:
 

using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

 
And override the SelectTemplateCore function. As a result, we get the following code:
 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace MyReader
{
    class MyDataTemplateSelector : DataTemplateSelector
    {
        protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
        {
            return base.SelectTemplateCore(item, container);
        }
    }
}

 
Now, in the XML file, we need to define the templates from which we will retrieve data. To do that we open GroupedItemsPage.xaml and go to the page resources where we have the CustomItemTemplate template defined:
 

<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>

 
Define one more template with minimum changes: let’s change alignments:
 

<DataTemplate x:Key="CustomItemTemplate2">
    <Grid HorizontalAlignment="Right">
        <Border Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}">
            <Image Source="{Binding Image}" Stretch="UniformToFill"
                    AutomationProperties.Name="{Binding Title}"/>
        </Border>
        <StackPanel Background="{StaticResource ListViewItemOverlayBackgroundThemeBrush}" VerticalAlignment="Top">
            <TextBlock Text="{Binding Title}" Foreground="{StaticResource ListViewItemOverlayForegroundThemeBrush}"  
                       Height="90" Margin="15,0,15,0" FontSize="30" />
        </StackPanel>
    </Grid>
</DataTemplate>

 
We get back to our class – MyDataTemplateSelector and add the code that defines a template to be used depending on the element of the group that is displayed:
 

using MyReader.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace MyReader
{
    class MyDataTemplateSelector : DataTemplateSelector
    {

        public DataTemplate Template1 { get; set; }
        public DataTemplate Template2 { get; set; }

        protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
        {
            RSSDataItem dataItem = item as RSSDataItem;
           
            if (dataItem.Group.UniqueId.Contains("stas"))
            {
                return Template1;
            }
            else
                return Template2;
        }
    }
}

 
Come back to the GroupedItemsPage.xaml and go the page resources where the templates are defined and initialize our selector:
 

<local:MyDataTemplateSelector x:Key="MyDataSelector"
                              Template1="{StaticResource CustomItemTemplate}"
                              Template2="{StaticResource CustomItemTemplate2}"/>

 
And now we indicate the selector to the place where the template for Item for local:VariableSizeGridView: is defined:
 

<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}}"
            ItemTemplateSelector="{StaticResource MyDataSelector}"
            SelectionMode="None"
            IsSwipeEnabled="false"
            IsItemClickEnabled="True"
            ItemClick="ItemView_ItemClick">

 
Run the application to make sure that everything works as planned.
 
Selector work result
 
Great! Everything works in the way it should and we can proceed to the live tiles.
But before moving to the tiles, let’s change style of the label text on the tiles of a group.
 
We create the required styles based on the BasicTextStyle style and place them in the resources of the GroupedItemsPage.xaml page:
 

<Style x:Key="ExtendedTextStyle" TargetType="TextBlock" BasedOn="{StaticResource BasicTextStyle}">
   <Setter Property="LineHeight" Value="40"/>
   <Setter Property="LineStackingStrategy" Value="BlockLineHeight"/>
   <!-- Properly align text along its baseline -->
   <Setter Property="RenderTransform">
      <Setter.Value>
         <TranslateTransform X="-1" Y="4"/>
       </Setter.Value>
    </Setter>
</Style>

<Style x:Key="ExtendedTitleTextStyle" TargetType="TextBlock" BasedOn="{StaticResource ExtendedTextStyle}">
     <Setter Property="FontWeight" Value="SemiBold"/>
</Style>

 
And apply this style to the templates text:
 

<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}"  
                       Style="{StaticResource ExtendedTitleTextStyle}" Height="90" Margin="15,0,15,0" FontSize="30" />
        </StackPanel>
    </Grid>
</DataTemplate>

<DataTemplate x:Key="CustomItemTemplate2">
    <Grid HorizontalAlignment="Right">
        <Border Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}">
            <Image Source="{Binding Image}" Stretch="UniformToFill"
                   AutomationProperties.Name="{Binding Title}"/>
        </Border>
        <StackPanel Background="{StaticResource ListViewItemOverlayBackgroundThemeBrush}" VerticalAlignment="Top">
            <TextBlock Text="{Binding Title}" Foreground="{StaticResource ListViewItemOverlayForegroundThemeBrush}"  
                       Style="{StaticResource ExtendedTitleTextStyle}" Height="90" Margin="15,0,15,0" FontSize="30" />
        </StackPanel>
    </Grid>
</DataTemplate>

 
Run the application and see how the grouped elements labels look like.
 
Group tiles
 
Everything looks so much better! If needed, it’s possible to play with styles longer to get the desired effect.
 
Adding live tiles
 
Now it’s time to add live tiles. Since we don’t have a service that checks the upgrades, our tiles will be renewed at the moment of obtaining RSS to please a user up to the next time s/he runs the application.
 
We go to the RSSDataSource.cs file and add the UpdateTilemethod to the RSSDataSource class:
 

public static void UpdateTile()
{
    var news = RSSDataSource.AllGroups[0].Items.ToList();            
    var xml = new XmlDocument();
    xml.LoadXml(
        string.Format(
            @"<?xml version=""1.0"" encoding=""utf-8"" ?>
    <tile>
        <visual branding=""none"">
            <binding template=""TileSquarePeekImageAndText03"">
                <image id=""1"" src=""ms-appx:///Assets/Logo.png"" alt=""alt text""/>
                <text id=""1"">{0}</text>
                <text id=""2"">{1}</text>
                <text id=""3"">{2}</text>
                <text id=""4"">{3}</text>
            </binding>
            <binding template=""TileWidePeekImageAndText02"">                        
                <image id=""1"" src=""ms-appx:///Assets/Habr_WideLogo.png"" alt=""alt text""/>
                <text id=""1"">{0}</text>
                <text id=""2"">{1}</text>
                <text id=""3"">{2}</text>
                <text id=""4"">{3}</text>
            </binding>  
        </visual>
    </tile>",
            news.Count > 0 ? System.Net.WebUtility.HtmlEncode(news[0].Title) : "",
            news.Count > 1 ? System.Net.WebUtility.HtmlEncode(news[1].Title) : "",
            news.Count > 2 ? System.Net.WebUtility.HtmlEncode(news[2].Title) : "",
            news.Count > 3 ? System.Net.WebUtility.HtmlEncode(news[3].Title) : ""));
    TileUpdateManager.CreateTileUpdaterForApplication().Update(new TileNotification(xml));
}

 
Don’t forget to add the following directives to the using block:
 

using Windows.Data.Xml.Dom;
using Windows.UI.Notifications;

 
Here we create XML to refresh tiles using templates and refresh the tiles themselves. The code is completely transparent. Since it’s just a sample, I always simply take the first RSS thread.
 
To make it work we need to add invocation of this method to any place where RSS is already available. Let’s add “await” to the AddGroupForFeedAsync calling methods of RSS loading and then we can simply call our function after adding the first feed.
 
Move to the LoadState method in the GroupedItemsPage.xaml.cs file, add async to it, and add the UpdateTile invocation to the AddGroupForFeedAsync methods::
 

protected async override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
{
   this.DefaultViewModel["Groups"] = RSSDataSource.AllGroups;

   await RSSDataSource.AddGroupForFeedAsync("http://blogs.msdn.com/b/stasus/rss.aspx");
   RSSDataSource.UpdateTile();
   RSSDataSource.AddGroupForFeedAsync("http://www.spugachev.com/feed");
}

 
I intentionally left one of the invocations without await – pay attention how it looks when you start the application.
 
Now it’s necessary to add WideLogo support to the application. Create Habr_WideLogo.scale-100.png file of the following size: 310×150, add it to the Asset folder. Double click on the Package.appxmanifest file to open its visual editor and add WideLogo to the application:
 
Adding WideLogo
 
Now we are ready to run the application. Run it and then close. Go to the Start screen and make sure that tiles – both square and rectangular – work properly.
 
Now it’s time to add contracts. Let’s start with the Share contract. Implement data sources. We will share data on the RSS post page and provide maximum data to the system.
 
Proceed to the ItemDetailPage.xaml.cs page code. To transfer data to the system, it’s necessary to handle DataRequested event for DataTransferManager. Let’s begin.
 
Adding Share contract
 

Register DataRequested event handler in the page NavigateTo (and unsubscribe from the NavigateFrom event), implement a handler that will provide post name and text to the system:
&nbsp;
protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);
            DataTransferManager.GetForCurrentView().DataRequested += Share_DataRequested;
        }

        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            base.OnNavigatedFrom(e);
            DataTransferManager.GetForCurrentView().DataRequested -= Share_DataRequested;
        }

        private void Share_DataRequested(DataTransferManager sender, DataRequestedEventArgs args)
        {
            var selectedItem = (RSSDataItem)this.flipView.SelectedItem;

            args.Request.Data.Properties.Title = selectedItem.Title;
            args.Request.Data.Properties.Description = selectedItem.Content;
            args.Request.Data.SetText(selectedItem.Content);            
        }

 
Run application, go to the post page and check if the application can pass data to other applications.
 
Addi9ng share contract
 
In fact, we get more data to share in the RSS feed. This is post picture, post URL, etc. I suggest you to modify code of the feed addition method and of the corresponding classes to get more data. The more data there is available the more applications to share with.
 
Sudden desire to tell about DataTemplateSelector made the article quite extended. That is why I will have to write the third part. Search contract, settings, background parallax and other useful tips will be described there. If there is too much information for the post, I will add more articles.
 
Current application code can be downloaded from SkyDrive using the link: aka.ms/w8RSSp2
 

June 13th, 2013

Leave a Comment