To CXML or not to CXML

[Updated: 09/03/2011]

—————

So it didn’t take me long to find out that this could have been done better.  So code and explanation has been updated.

—————

After what has seemed like forever, the new Silverlight 5 PivotViewer is now available to the public.  As most of you probably know, it did not make the beta and everyone assumed that we would be waiting until the final release before the public would get a copy.  However, the Silverlight team, being the awesome team that they are, decided to cut loose a RC.  If you don’t have it yet, make sure you go download it here:

http://www.silverlight.net/downloads

It has a bunch of great new stuff in it and a lot of improvements to the new things that you saw in the beta.  We will be going over a lot of it in the coming weeks and months, but for now back to my old stomping ground, the PivotViewer.

 

Old vs New

The PivotViewer has a ton of changes and new features in it.  A lot more detail than a single post can cover.  However, the two most noticeable features are the client side collection binding and the XAML templates.  You are no longer required to go thru the painful process of creating a CXML file with all of your metadata in it and a DeepZoom collection for all of your visuals.  Or do you?  We will get back to that question in a little bit.

In the new PivotViewer, you only need 3 things to create your collection:

  • Data
  • PivotProperties
  • ItemTemplates

Instead of loading your meta data into the PivotViewer via a CXML file, you can simply set the ItemsSource property to your collection of items.  PivotProperties are simply a replacement for Facets in the original PivotViewer.  Your ItemTemplates are your DataTemplates needed to render your collection.  And that’s it.  Piece of cake right?

When you compare it to the previous method, it can be fairly simplistic to get up and running.  In fact, most conversations I have had on the subject, people are very happy to see CXML go.

 

Out with the Old?

So now that we have this neat cool away of creating our pivot collections, why I am even talking about CXML?  Well it’s a good question and one I can hopefully answer.  However, before I get there, let’s look under the covers of how the new PivotViewer works.

Under the hood, the PivotViewer is really the same beast.  It is still an image based system that is built on the DeepZoom technology.  But wait, how can that be?  We have cool XAML templates now, those aren’t images.  Well…. Actually they are.  PivotViewer takes the templates and renders them to the appropriate images based on resolution, etc.  So don’t think about adding interactive controls to your templates and expect them to work (I’ll show you how to do that later… Smile ).  Now, this is still a huge step forward from where we were.  PivotViewer uses those templates and databinding to update the images in the collection when your size and/or data changes.  Pretty slick stuff when you sit back and think about it.  However, for our discussion, it’s really just important to know we are having images generated.

So why is this important to us and what bearing does it have on CXML collections?  Let’s look at an example.  If you haven’t seen the Netflix example, jump over and take a look at it now at : http://netflixpivot.cloudapp.net/

image

As you can see, the trading cards are simply the movie cover art.  Another example would be the MIX 10 session collection that I use as a demo in PivotViewerLessons here : http://pivotviewer.championds.com.  Each trading card is nothing more than a screen shot from each session.

image

In both of these cases, our trading cards are nothing more than a single image.  Now I know what you are thinking, “perfect, my templates will be as easy as adding an image tag!”  And you would be correct.  It would be very possible to replicate this collection in the SL5 PivotViewer with a simple template. 

So why is this not necessarily the best way to go?  If you spent much time with the existing PivotViewer, you know that each trading card itself is a DeepZoom image.  This means that there are multiple resolutions of each trading card generate when you create the collection.  When you load the initial collection in the PivotViewer each trading card is loaded in a very low resolution.  This prevents you from having to download a massive amount of imagery in order to get started.  As you zoom in to an image, higher quality versions of that image are downloaded and replace the lower resolution image.  This is done numerous times until you get to the highest quality images.  That’s how you are able to load 3,000 images at once in a rather short time and is what makes DeepZoom, and thus PivotViewer, so effective.

Now let’s take a step back and look at our idea of creating an XAML template to replace a collection.  In each of two cases above, for a collection to load, the PivotViewer would have to download each image (in a high resolution form), then generate the trading cards on the client.  If you do this, then you are effectively negating the benefits of DeepZoom.  For even a small collection, this could create a bad experience for you user.  So if our cards consists of high resolution images or a series of images, dynamic client side collections might not be the best route to go.

 

Using CXML in the new PivotViewer

So what happens if you want to use the new PivotViewer with a new or existing CXML collection.  The LoadCollection() method no longer exists and the only way to get data into the PivotViewer is to use the ItemsSource or DataContext.  Doesn’t really work well with the new PivotViewer.

So what do you need for the new PivotViewer again?

  • Data
  • PivotProperties
  • ItemTemplates

Luckily, it looks like there is a solution to map our CXML to the 3 things that the PivotViewer needs. (**note: this has yet to be documented, so the following code is from some investigative work)  The PivotViewer has a class CxmlCollectionSource.  After examining this class a bit, it looks like it loads in the CXML (you can pass a Uri in the constructor) and generates the items we need.  Once the data has been loaded, you can simply map the collections to your PivotViewer.

Let’s take a look at what this should look like.  The collection being loaded is the public collection I have of the MIX 10 sessions (I really should update that).

        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 = 
                           _cxml.ItemTemplates;
                pViewer.ItemsSource = 
                           _cxml.Items;
            }
        }

 

The CxmlCollectionSource has a State property: Initializing, Loading, Loaded, Failed.  This will let you track when the object has completed the download and processing of your CXML file.  This is a great time to map our 3 components over.  If you look at the PivotProperties collection that is created, it should be look familiar to your Facet collection that you have in your CXML.  However, you will notice a few additional properties in the collection.  Name, Description, and Href have been added to account for the default attributes of each item in the collection.  In addition there are a couple of properties added to your DeepZoom collection.  These properties map your item to the actual DeepZoom hierarchy that was created for that item.

You might be wondering what I was wondering, how is the new PivotViewer going to handle the multiple resolutions of the image?  It’s a valid question and I decided to dig a little deeper to find out.  If you look at the ItemTemplates collection you will see they are only returning a single template.  I thought this was a little odd.  However, if you look at the template you will see the heart of the template is a PivotViewerMultiScaleSubImageHost control.  I couldn’t resist, I had to check it out and see what was going on. It’s a nifty little class that basically downloads the appropriate image based on size as the trading card size changes.  So it answered the question, it is holding true to the DeepZoom scaling and should be a scalable way to go.

 

When to Use CXML

So now that we know its possible to load the original CXML collections into the PivotViewer, when should we use it?  I see two main reasons really: image intensive based collections and existing collections.  Outside of the new dynamic collections, there are a lot of new customization end points in the new PivotViewer.  So now you are able to move to the new PivotViewer, take advantage of all of the new features, and not have to throw away all of your hard work that you spent in generating your collections.

There is a lot of great stuff in the new PivotViewer and the rest of SL5 for that matter.  So make sure you head back as we start digging thru some of it.

Download the sample project above here : SL5CXMLPivotViewer.zip

12 Responses

  1. Hi Tony

    Great post! This info will really help in assessing which is the right way to go, and also might explain why we have experienced some performance problems with the pre-release version of the pivotviewer control when displaying a large number of trade cards. One thought occurs to me though – do you think there is a practical limit on the number of tradecards which can be displayed when using a non-CXML collection as a source, even if they are not image based?

    Many thanks

    Chris Ballard

  2. Chris,

    The word I received earlier this year is the limit would be the same as the previous version (3-5k). We will have to see if the final solution will hold up to that, but I know that was the performance target.

  3. Hi Tony ,
    My requirement is that i need a pivot viewer that does everything on client side , and an image creation module too on client side . In short i would be receiving text from a data base and want to show it and create cxml on client side itself as the system where it will be hosted does not support IIS or windows formart.

    Is it possible. If so , can you please share a sample with me. Also the sample link given by you is not working.

    Thanks and regards,
    Raj

  4. Hi Tony,

    ItemProperties does not seem to have a ToList() method in the released version.

    Thanks,
    Ben

  5. I’m using a dynamically generated CXML as source (generated via a HTTP Handler).
    The Problem is that the CxmlCollectionSource fails to load the CXML (getting a There is an error in XML document (0, 0)).

    I made a workaround where I load my CXML via the WebClient.DownloadStringAsync method. Once the CXML is loaded with the WebClient the CxmlCollectionSource is able to access the CXML source (properly because it’s using the browser- cached version).
    Leaving a static CXML on the server also worksfine.

    My best guess is that CxmlCollectionSource has a very low timeout (my CMXL i generated an loaded in approx. 150ms)
    Have You any experince with dynamic CXML’s?

  6. Hi Tony

    Have been trying to run your app (and also the PivotViewerLessons app from codeplex), but am runing up against a problem when it tries to load from http://labs.championds.com/MIX10/MIX10Collection.cxml.
    This link does not work for me, from either application. Also, in the PivotViewerLessons app, it references a ColorPicker.dll, which isn’t bundled into the zip file.

    Sorry to burden you with this stuff, but I’d love to get to grips with the PivotViewer control, and your code looks like a great place to start!

    Thanks

    Ade

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.