Dynamically generated columns in a HubSection for a Windows Store App

In the default implementation generated by Visual Studio 2013 for a Hub-like Windows 8.1 application, you will get a nice section by section layout. However, if you need to provide a column-based layout in one of the sections, there are a few hurdles to overcome. Robert Evans shows you how!


If you come from the WPF world, you would pick a FlowDocument; but it is not supported in Windows Store Apps. I want to show you something you might not have noticed, especially if you are just getting started with Windows 8.1: the GridView appplication template provided by Visual Studio 2012 for Windows 8 Apps creates the RichTextColumns control, a very useful wrapper for RichTextBlock. It creates as many additional overflow columns as needed to fit the available content. This is a very useful control that can be reused in a variety of different scenarios, including what we are trying to achieve here. Since this helper class was removed in the default GridView App template of Visual Studio 2013 for Windows 8.1, I needed to copy it from a Visual Studio 2012 implementation.

The second hurtle to overcome is related to binding. The RichTextColumns control uses RichTextBlock which does not support direct binding as there is no dependency property for you to bind to. This makes it challenging to bind your collection of items with string and image properties. One solution is to create a IValueConverter type that accepts a list<FeedItem> and creates a RichTextBlock to format the elements of the list. And this RichTextBlock object is exactly what is expected by the RichTextContent property of the RichTextColumns control!

 public object Convert(object value, Type targetType, object parameter, string language)
{
    var list = (List<FeedItem>)value;
    var rtb = new RichTextBlock() { LineStackingStrategy = LineStackingStrategy.MaxHeight, 
 Width = 560 };

    foreach (var item in list)
            rtb.Blocks.Add(GetSingleRTB(item));

    return rtb;
}

private Block GetSingleRTB(FeedItem item)
{
    var p = new Paragraph();

    // Title
    var bold = new Bold() { FontSize = 24, FontFamily = new FontFamily("Segoe UI Light") };
    bold.Inlines.Add(new Run() { Text = item.Title });
    p.Inlines.Add(bold);

    // Content
    p.Inlines.Add(new Run() { FontSize = 11, FontFamily = new FontFamily("Segoe UI"), 
 Text = item.Content });
     // ImageUrl
    p.Inlines.Add(new InlineUIContainer() { Child =  new Image() { Width = 250, Source =
 new BitmapImage(new Uri(item.ImageUrl))}});
     p.Inlines.Add(new LineBreak());
    p.Inlines.Add(new LineBreak());

    return p;
}

The converter instance is defined in the application resources:

 <ResourceDictionary>
    ...
    <converters:FeedDatatoRtfBlock x:Name="FeedDatatoRtfBlock" />
</ResourceDictionary>

So it can be reused for bindingin any page like this:

 <HubSection Header="Dynamic Columns (databound)">
    <DataTemplate>
        <common:RichTextColumns x:Name="richTextColumns" Margin="3,10,3,10" 
                RichTextContent="{Binding Path=Items, Converter={StaticResource 
 FeedDatatoRtfBlock}}">
             <common:RichTextColumns.ColumnTemplate>
            ...
        </common:RichTextColumns>
    </DataTemplate>
</HubSection>

Download the code for this article here.


Original content from Robert Evans; posted by MSPFE editor Arvind Shyamsundar