Extending your CXML Trading Cards in Silverlight 5

In my last post To CXML or not to CXML I mentioned that I found a nifty little user control being used in the single ItemTemplate being returned from the CxmlCollectionSource.ItemTemplates, the PivotViewerMultiScaleSubImageHost (yep, that’s a mouth full).  For a brief recap, this control uses the DeepZoom information for each item in your collection, then downloads and displays the appropriate resolution image.  This allows you to keep to the DeepZoom benefits of scaling and prevents you from downloading the full images and delaying the initial load of the collection.

So I figure if the CxmlCollectionSource can use this little control, why can’t we? Before we get into how we are going to use it, let’s look at how we duplicate what the CxmlCollectionSource is doing.  The ItemTemplates property returns a PivotViewerItemTemplateCollection with a single template in it that looks like this:

<pivot:PivotViewerItemTemplate>
    <pivot:PivotViewerMultiScaleSubImageHost
      CollectionSource="{Binding [VisualCollectionSource][0] }" 
      ImageId="{Binding [VisualImageId][0]}"/>
</pivot:PivotViewerItemTemplate>

 

You can see that it has two properties that we need to address: CollecitonSource and ImageId.  Since we are only duplicating functionality right now, we can use this template as is.  Stealing some code from my last article, let’s put a similar template in our page’s Resources like such (only adding a Key for us to reference in code)’:

<pivot:PivotViewerItemTemplate x:Key="smallTemplate">
    <pivot:PivotViewerMultiScaleSubImageHost 
           CollectionSource="{Binding [VisualCollectionSource][0] }" 
           ImageId="{Binding [VisualImageId][0]}"/>
</pivot:PivotViewerItemTemplate>

 

Now we can use our template in our code base:

private CxmlCollectionSource _cxml;
void pViewer_Loaded(object sender, RoutedEventArgs e)
{
    _cxml = new CxmlCollectionSource(new Uri("http://labs.championds.com/MIX10/MIX10Collection.cxml",
                                            UriKind.Absolute));
    _cxml.StateChanged += _cxml_StateChanged;
}

void _cxml_StateChanged(object sender,
                       CxmlCollectionStateChangedEventArgs e)
{
    if (e.NewState == CxmlCollectionState.Loaded)
    {
          pViewer.PivotProperties =
                     _cxml.ItemProperties.ToList();
          pViewer.ItemTemplates = new PivotViewerItemTemplateCollection();
          pViewer.ItemTemplates.Add((PivotViewerItemTemplate)Resources["smallTemplate"]);
          pViewer.ItemsSource =
                      _cxml.Items;
    }
 }

This code is exactly like the last post’s code, with the exception that we are not using the ItemTemplates from the CxmlCollectionSource and are setting our own.  If you run this, you should get identical results from last project in To CXML or not to CXML.  That will give us a base line for where to go next.

 

Adding some XAML to our CXML Collection

One of the coolest new features in the SL5 PivotViewer is the ability to have different templates at different sizes (or resolutions).  In order to accomplish this in the SL4 PivotViewer you had to get very creative with splicing DeepZoom collections together.  Now it is much simpler.  The purpose of this feature is to allow you to present the user more information the closer they zoom into an image.

What if we decided to add some additional content to our trading cards.  In the above example we are using a collection from the MIX 10 videos.  Each card is nothing more than a video capture at the beginning of each session.

image

With the new features and a little help from our short named friend, we can extend our trading cards with very little effort.  If we extend our template from above to look like following, we can start to add additional information to our cards.

<pivot:PivotViewerItemTemplate x:Key="largeTemplate">
    <Grid Width="900" Height="1000" Background="LightGray">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <pivot:PivotViewerMultiScaleSubImageHost  CollectionSource="{Binding [VisualCollectionSource][0] }" ImageId="{Binding [VisualImageId][0]}"/>
        <Grid Margin="20" Grid.Row="1">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <TextBlock Text="{Binding [Name][0]}" FontSize="28" TextWrapping="Wrap"/>
            <Grid Grid.Row="1">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition Width="Auto"/>
                </Grid.ColumnDefinitions>
                <TextBlock Text="{Binding [Description][0]}" FontSize="20" TextWrapping="Wrap" Margin="0,20, 0, 0"/>
                <StackPanel Orientation="Vertical" Margin="20,20,20,0" Grid.Column="1" Width="300">
                    <TextBlock Text="Speakers" FontSize="24"/>
                    <ListBox ItemsSource="{Binding [Speakers]}" FontSize="22"/>
                </StackPanel>
            </Grid>
        </Grid>
    </Grid>
</pivot:PivotViewerItemTemplate>

The new template will give our trading cards a bit more detail while keeping us from regenerating our images and keeping the DeepZoom advantages.

image

Once we added our new template to our XAML resources, then we simply need to add the template to our ItemTemplates:

void _cxml_StateChanged(object sender,
                        CxmlCollectionStateChangedEventArgs e)
{
    if (e.NewState == CxmlCollectionState.Loaded)
    {
        pViewer.PivotProperties =
                    _cxml.ItemProperties.ToList();
            pViewer.ItemTemplates = new PivotViewerItemTemplateCollection();
        pViewer.ItemTemplates.Add((PivotViewerItemTemplate)Resources["smallTemplate"]);
        pViewer.ItemTemplates.Add((PivotViewerItemTemplate)Resources["largeTemplate"]);
        pViewer.ItemsSource =
                    _cxml.Items;
    }
}

 

One last little item that we need to do is to modify our original “smallTemplate” and set a MaxWidth to it.

<pivot:PivotViewerItemTemplate x:Key="smallTemplate" MaxWidth="300">

The MaxWith property is what the PivotViewer uses to determine when to switch templates.  The PivotViewer will use the first template in the collection, until the MaxWidth is hit, then it will switch to the next in line.  If you set a MaxWidth on the last template in the collection and the card size exceeds that then a blank image will be generated.

If we run our solution now, then the initial collection should look familiar.  As you zoom in, then cards will change to something similar to what you see in the image above.

This will give us a lot of flexibility in extending our existing collections.  In addition, we can also create image intensive collections and use DeepZoom to keep our initial data loads down.

Something to think about as you are exploring the possibilities with the new PivotViewer.

You can download the source code here: SL5ExtendCXMLCards.zip

One response

Leave a Reply

Your email address will not be published. Required fields are marked *

.NET development is constantly changing and expanding. With over 20 years in the industry, I have had the opportunity to see this the technology and the community grow and shift. To get weekly updates and insights into the world of .NET, development, and career advancement click the subscribe button.