Follow Me on Instagram Subscribe via RSS Feed

PivotViewer Basics : Dynamic Collections

December 5, 2011

One of the features that prevented many projects from using the original PivotViewer was the static nature of the collection.  Once a collection was loaded it was not possible to modify any of the trading cards within that collection.  This limited the potential workflows that PivotViewer could be used to implement.  The Silverlight 5 PivotViewer changes all of that.  PivotViewer now responds to changes within the collection as well as changes to the individual objects themselves.  The best thing about this new feature is that we don’t have to make any changes to the PivotViewer to take advantage of this.

If you have followed the other posts in the PivotViewer Basics series, you have seen that we now set our data for our collections via basic Silverlight data binding through the ItemsSource property.  Whether you are using this approach or importing a CXML file, as discussed in Extending your CXML Trading Cards, both are now capable of dynamic updates.

Adding to a Collection

I’ve often heard complaints about the speed in loading several thousand items into a collection.  While the PivotViewer handles this very well, it still simply takes time to download all of that data and then process it.  The advantage of using an ItemsSource that supports INotifyCollectionChanged, such as an ObservableCollection, is that we no longer have to load our entire collection at once. 

In order to provide a better user experience, we can now break up the data loading into more manageable chunks.  By loading a smaller group, say 100 items, we can quickly get information in front of the user.  Then, as more information is downloaded, we can continue to add to the collection.  This tends to be a more desirable experience than waiting for a single download.

Since we are continuing with our series,   we are going to start off with the project we finished in the Semantic Zoom post.  If you do not have that project, you can download it here : PVB02_SemanticZoom.zip

To demonstrate paging our data into the collection, we are going to start off by adding a button to our UI that will be responsible for adding data.  So we will modify our new UI to look like this:

<Grid x:Name="LayoutRoot" Background="White">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="Auto"/>
    </Grid.ColumnDefinitions>
    <pivot:PivotViewer x:Name="pViewer">
        <pivot:PivotViewer.PivotProperties>
            <pivot:PivotViewerNumericProperty 
        Id="Value" 
        Options="None" 
        Binding="{Binding Value}"/>
            <pivot:PivotViewerStringProperty 
        Id="Data1" 
        Options="CanFilter,CanSearchText" 
        Binding="{Binding Data1}"/>
            <pivot:PivotViewerStringProperty 
        Id="Color" 
        Options="CanFilter,CanSearchText" 
        Binding="{Binding Color}"/>
            <pivot:PivotViewerDateTimeProperty 
        Id="Stamp" 
        Options="CanFilter" 
        Binding="{Binding Stamp}"/>
        </pivot:PivotViewer.PivotProperties>
    </pivot:PivotViewer>

    <StackPanel Grid.Column="1" Margin="20, 20, 20, 0">
        <Button x:Name="btnAdd" Content="Add Items"
                Width="85" Height="25"
                Click="btnAdd_Click"/>
    </StackPanel>
</Grid>

Next we will move the data generation code to our button click event.  I’ve also made a slight change to the data generation class (DemoItem) that will enable us to define the starting number.  Below are the changes to the code behind and our data class.

(MainPage.xaml.cs)

public MainPage()
{
    InitializeComponent();

    pViewer.ItemsSource = new ObservableCollection<DemoItem>();

pViewer.ItemTemplates = new PivotViewerItemTemplateCollection()
{
    (PivotViewerItemTemplate) Resources["DemoTemplate"],
    (PivotViewerItemTemplate) Resources["DemoTemplate2"]
};

}

private void btnAdd_Click(object sender, RoutedEventArgs e)
{
    var coll = pViewer.ItemsSource 
                    as ObservableCollection<DemoItem>;

           
    var data = DemoItem.BuildData(coll.Count, 100);

    foreach(var itm in data)
        coll.Add(itm);
}

(DemoItem.cs)

public static ObservableCollection<DemoItem> BuildData()
{
    return BuildData(0, 100);
}

public static ObservableCollection<DemoItem> 
    BuildData(int start, int size)
{
    var data = new ObservableCollection<DemoItem>();

    for (int i = start; i < start + size; i++)
    {
        var itm = new DemoItem() 
            { ShortName = i.ToString("000") };

        var mod = i % 3;

        switch (mod)
        {
            case 0:
                itm.Color = "Blue";
                break;
            case 1:
                itm.Color = "Red";
                break;
            case 2:
                itm.Color = "Green";
                break;
        }

        itm.Data1 = i % 2 == 0 ? "Even" : "Odd";
        itm.Stamp = DateTime.Now.AddDays(-1 * i);
        data.Add(itm);
    }

    return data;
}

Now if you run your application, your PivotViewer will load with an empty collection and we will have a new button on the right hand side. Clicking the button the first time will generate the original collection that we have used during the series.

image

Clicking our new button will generate another 100 items and add them to our ItemsSource.  So now we have an updating collection.

Dynamic Item

One of the coolest features, from my point of view anyway, of the new PivotViewer is the ability to dynamically update your trading card.  In the original version, it required a collection reload to update any of the cards.  Now it is just a simple matter of having your objects in the ItemsSource implement the INotifyPropertyChanged interface.

If you take a look at our data class, you will notice that we have already implemented the INotifyPropertyChanged interface.  So the majority of our work is already completed.  To demonstrate this feature, let’s add a new button to our UI:

<StackPanel Grid.Column="1" Margin="20, 20, 20, 0">
    <Button x:Name="btnAdd" Content="Add Items"
            Width="85" Height="25"
            Click="btnAdd_Click"/>
    <Button x:Name="btnChange" Content="Change Items"
            Width="85" Height="25"
            Click="btnChange_Click"/>
</StackPanel>

The code behind for this button is rather straight forward.  All we are doing is spinning through our collection and changing all of our “Green” cards to “Purple”.  I’ve added a state boolean so that we can switch back and forth between green and purple.

private bool isGreen = true;
private void btnChange_Click(object sender, RoutedEventArgs e)
{
    var oldValue = isGreen ? "Green" : "Purple";
    var newValue = isGreen ? "Purple" : "Green";
    isGreen = !isGreen;

    var coll = pViewer.ItemsSource
                    as ObservableCollection<DemoItem>;

    foreach (var itm in coll)
        if(itm.Color == oldValue)
            itm.Color = newValue;
}

If you run the application and add some data to the collection, you can now dynamically modify the color of our “Green” cards.

image

These new dynamic features of the PivotViewer dramatically expands the possibilities for how it can be incorporated into your applications. 

You can download the code here: PVB03_DynamicCollections.zip

Next Post…

Continuing with this series, the next post will take a closer look at the new API and see how we can take advantage of it in our applications.

Series Navigation<< PivotViewer Basics : Semantic ZoomPivotViewer Basics : Basic Item Adorners >>

Comments (9)

Trackback URL | Comments RSS Feed

  1. SRK says:

    Great posts. I like all postings.

    Is it possible to add custom actions in XAML pivotviewer? I know double click is way to handle. I am just checking.

    Thanks

  2. VK says:

    Great posts! Very helpful.

    I have a question about this series of tutorials. Actually, two:

    1. You’ve mentioned four types of properties in the first part. Among them was PivotViewerLinkProperty. Do you know how to form/bind/convert one?

    2. It there a way in this new PV to sort by a propery, but not to list it in the left-hand menu? Clarification: I have a data set with offices, departments, etc. I added them all as properties to my PV. I’m trying to find a way to sort everything A-Z on Name though (person’s name) by default without having the Name as an option in the left pane. Is there a way?

    Thank you!

  3. Tony Champion says:

    I will put a post together for the PivotViewerLinkProperty.

    As far as #2, the PV does is an either/or. You can’t put it in the sort and not the filter.

  4. VK says:

    Tony,

    Thank you for the response. I’m looking forward to reading your PivotViewerLinkProperty post.

    As far as sorting/filtering go, is there a way to prioritize the sorting order in any way other than a simple order of appearance? I have 2,000+ names that I will be forced to display in the left-hand pane (since I cannot otherwise have a filter on the names), but if I can put it to the bottom of available grouping categories while retaining sort by name as a default/dominant sort, it may not be as bad. I know there is a way to achieve this (sort of) in the older Pivot Viewer version, so there must be something in the new version – at least it logically makes sense to have something like that.

    That is, if you have a library of movie titles, for example, you may want to sort/filter by Title, Year, Director, Producer, Studio, Genre, etc. Let’s say you chose to sort by Genre. Wouldn’t you want to have an option to have the movies listed in an alphabetical order in each “bucket” (Genre)? Or is it just my OCD talking?

    Thank you!

  5. Bruce McMillan says:

    Hi Tony,
    Thanks for posting this, I have been playing with pivot and Cxml for a short wihle now and the options of creating Dynamic collections etc is much more exciting than the old days of demoing the netflix feed !

    Quick question, I am using MVVM as a basis for this so am quite easily to create collections / propertiy collections etc, but I seem to be getting stuck with trying to create templates in the View Model. The key issue is migrating your code behind section where you add the resoruces refrenced in the view as user control resoruces.

    Ideally i’d like to create these in Global or merged dictionayies and then bind them as a collection.

    Have you tried this at all ?

    Regards

    Bruce

  6. Tony Champion says:

    You can add a PivotViewerItemTemplateCollection to your dictionary. Then it would be just a matter of setting the property on the Pivotviewer to that StaticResource (either in code in XAML)

  7. VK says:

    Hi Tony,

    It was possible in the old PivotViewer to pass a symbol-separated string for it to break apart and display as separate items/facets. For example, let’s say there is a list of 100 people. The data set has 1 data row per parent. Each parent has First Name, Last Name, DOB fields as well as a field called Children. Each parent in this imaginary database can have 1 to [some number goes here] children. The children names are listed in the Children column and are separated by a delimiter. In the old PivotViewer, I could configure it so that when I see the detailed view for a parent’s “trading card”, I see the title Children, and underneath I’d see one or more children, each on a new line, and each clickable (i.e., click on one and it will be applied as a filter to the data set). If parent-children is not a good example, think of college grads + majors, or college grads + schools + degrees. Is there a way to achieve this in the new PivotViewer?

    Thanks!!

  8. Adam Wawrzyniak says:

    I have checked all your post on Pivot, they are great, I have learned a lot!

    I have a problem to find explanation how to Dynamically create cxml from the code, should I be using some xml? Some sites refer to PV v1, not v2 and I am not sure if I should follow those old solutions. In your examples, you mostly use DemoItem class, which is also easy to replace with reference to existing cxml, generated by Pivot in Excel (explained nicely in your tutorials), but how to build collection dynamically?

    I hope for some advice, thanks!

Leave a Reply