This post is the end of the article
How to use PivotViewer for Silverlight in a real project .
Now our application already has a page that can display a test collection of data (our prototype). Moving on to the next step ...
Step 4, software generation of xml with data and images in Deep Zoom format
We need to create a .cxml file with xml data and convert the images of the elements into Deep Zoom format. In principle, xml can be easily created using standard .NET classes, and to work with Deep Zoom, use the Deep ZoomTools.dll library (part of the
Deep Zoom Composer ). But there is an even more convenient way -
Pauthor . This project includes both .dll, which can be called from your code, as well as a command line utility and allows you to create collections for Pivot, as well as to convert between these collections to other formats (CSV, Excel, CXML with raw images, and CXML with DeepZoom images) and back.
')
Pauthor is convenient in that it allows you to form a collection using high-level objects such as PivotCollection, PivotFacetCategory, PivotItem, etc. The example of using Pauthor is given in habrotopic.
We create PivotViewer site content in 10 minutes using the example of Habrahabr , so we will not dwell on it.
There is one useful point that can greatly improve the usability of our viewer. We do not want to force the user to poke at all the pictures in a row in order to understand what exactly (what product model, hotel or person) are drawn on them? It would be nice to place these names directly in the pictures. But usually we have just images of goods or something else without any signatures. So, when creating the Deep Zoom collection, Pauthor allows us to specify an html template, on the basis of which images will be formed. In addition to pure html, placeholders can be used in these templates, which will be replaced with the corresponding characteristics from the object description. Here is an example of a simple template:
< html >
< head >
< style >
body {
margin: 0px;
}
img {
position: absolute;
top: 0; left: 0;
width: 100%; height: 100%;
}
p {
font-size: 100px;
color: white;
background: grey;
position: absolute;
bottom: 0;
left: 0;
width: 100%;
filter: alpha(opacity=50);
padding: 20px;
}
</ style >
</ head >
< body >
< img src ="{image}" />
< p > {name} </ p >
</ body >
</ html >
* This source code was highlighted with Source Code Highlighter .
In the folder with Pauthor you can find several other examples. And here is an example of what can happen, taken from a
site that will allow you to choose a place for your wedding:

So, at first glance, everything is in order - we can programmatically create a collection with the data we need, and Pivot Viewer does the rest. But for more convenience, it does not hurt to add a couple of details. So…
Step 5, optional, but fine and useful doping of the element with a file :)
When the user selects one of the pictures, its detailed description appears in the property panel (on the right side of the Viewer). The title of the description is highlighted as a link, but what happens when you click on this link, the Viewer completely leaves it to our discretion.
In the same way, users are accustomed to the fact that a double click on an object takes the default action. The viewer handles double-click on the image in the same way as a click on the description title - it forms the event and leaves the decision for us.
To process them, add a couple of lines of code to the .xaml page in the Silverlight project:
<pivot:PivotViewer
x:Name= "MainPivotViewer"
LinkClicked= "OnPivotViewerLinkClicked"
ItemDoubleClicked= "OnPivotViewerItemDoubleClicked"
/>
/// <summary>
/// Handle links clicked in the metadata pane.
/// </summary>
private void OnPivotViewerLinkClicked(Object sender, LinkEventArgs args)
{
OpenLink(args.Link.ToString());
}
/// <summary>
/// Handle double-clicks on collection items
/// </summary>
private void OnPivotViewerItemDoubleClicked(Object sender, ItemEventArgs args)
{
String linkUriString = MainPivotViewer.GetItem(args.ItemId).Href;
if (! String .IsNullOrWhiteSpace(linkUriString))
{
MainPivotViewer.CurrentItemId = args.ItemId;
OpenLink(linkUriString);
}
else
{
// Error: No Associated Web Page: the item that was double-clicked has no value for the 'Href' field
}
}
* This source code was highlighted with Source Code Highlighter .
In our case, we call the OpenLink helper method, which opens a page with a description of the object in another browser window. It is quite possible, instead of going through the url, you will want to add selected objects to the basket or open some other collection of objects. In order not to increase the size of the description, the OpenLink code is not shown here. You can view it, as well as copy the rest of the event-handling code in the example from the Pivot folder (in my case, this is “C: \ Program Files (x86) \ Microsoft SDKs \ Silverlight \ v4.0 \ PivotViewer \ Jun10 \ Source” ).
This example contains another useful feature. Pivot Viewer allows you to add several user actions to each picture. Action is an action that can be performed on a selected object. For each action, you must specify an icon, a name, and a callback method. Then, when you hover the cursor over the picture, Pivot will display a list of available actions. Here is how it looks in the example from Pivot, in which actions are used to add / remove items from the cart:

And one more useful moment. When you view large amounts of data, every bit of space is dear to you. But many sites have a fixed layout and occupy only a part of the screen (a frequently encountered version in the formulation is to navigate the resolution of 1024px width). Silverlight applications have a very convenient opportunity to switch to full-screen mode, for this it is enough to change the value of the IsFullScreen property.
All we need is to somehow stick a button to the Pivot Viewer to change the mode, like this:
< Grid x:Name ="LayoutRoot" Background ="White" >
< pivot:PivotViewer
x:Name ="MainPivotViewer"
LinkClicked ="OnPivotViewerLinkClicked"
ItemDoubleClicked ="OnPivotViewerItemDoubleClicked"
/>
< Image
x:Name ="btFullScreen"
Width ="32" Height ="32" MinWidth ="32" MaxWidth ="32" MinHeight ="32" MaxHeight ="32"
Margin ="0,0,12,12"
HorizontalAlignment ="Right" VerticalAlignment ="Bottom"
Source ="{ }"
/>
</ Grid >
* This source code was highlighted with Source Code Highlighter .
and add a handler to it:
private static readonly BitmapImage imageOff = new BitmapImage({ });
private static readonly BitmapImage imageOn = new BitmapImage({ });
btFullScreen.MouseLeftButtonDown +=
delegate (Object s, MouseButtonEventArgs args)
{
if (Application.Current.Host.Content.IsFullScreen)
{
Application.Current.Host.Content.IsFullScreen = false ;
btFullScreen.Source = imageOn;
}
else
{
Application.Current.Host.Content.IsFullScreen = true ;
btFullScreen.Source = imageOff;
}
};
* This source code was highlighted with Source Code Highlighter .
For clarity, I change the pictures on the panels depending on the mode. Here is how it looks in
my case :

Five steps are completed and we can admire the result of our work. But this description would be little different from the usual "how to" if I had not shared my experience in solving problems that arose during development. Remember, at the very beginning of the article I wrote that we can stray a little through the forest? This is true, and the fault is the error handling in the Pivot control.
I have to say, in my opinion, it works quite stably. But for a couple of weeks of work, I twice stumbled upon a sad message a la "Silverlight plugin performed an incorrect operation and can not work further," but a simple reload of the page fixed everything. In general, taking into account all its advantages, it is still possible to ignore this, especially since this is only the first version.
But what made me spend time debugging was the error messages. Now I will talk about this in more detail, and you will remember two useful rules:
- If the Pivot simply stopped displaying something, you may have messed up with the data. Slip him a simple test collection. Earned? Then use the half division method to discard xml chunks from your original data, until you narrow the scope to the value \ attribute that is to blame for everything.
- If you managed to get some kind of error message (this is not always the case) - do not take it literally. Sometimes the text of the message has nothing to do with the real cause of the error.
Now go through the errors in more detail. By the way, do not forget that by the time you read this article, something can already be fixed, and something new can be added :)
- You have received the message “The element is already a child of another element” (or its equivalent in English).
Checked the structure of your xml - everything is in order? Then look at your operating system version. Losers with a 32-bit version of Windows 7 leave our ranks.
This error occurs when you try to load a collection into PivotViewer. You can walk through the forums and there will offer different reasons for this error. But it is extremely likely that the reason is the OS version. Even native examples from Microsoft don't work on it, and, like them, your code will work fine on the 64-bit version of Windows 7, and on other operating systems.
- You still receive the message “The element is already a child of another element,” although the first point clearly does not apply to you.
Possible cause - some errors in the values of the attributes of xml tags. In my case, the reason was that I mistakenly indicated in the p: Icon attribute of the Collection tag not the url to the image, but the physical path to the picture on my computer.
- You have received a funny message "Invalid type for String facet: String".
The reason is that you cannot specify empty strings as values for categories (FacetCategory) of type String. In this case, just do not add value at all.
- At one point, the data simply stopped being rendered without any error messages.
Possible reason - you use the separator "," for categories of type Number instead of ".". It is possible, I just did not understand how you can specify the desired culture info Pivot Viewer. At least, changing the Language property and explicitly specifying the culture in the web.config did not help, the Viewer persistently believed that only a dot could be the correct separator.
In my case, I just walked away from the problem. The number I used for the category “Game size (in MB)” and I thought that rounding it up to a whole value would only simplify the filter. If someone figure out how to solve this problem - write, I will correct the description.
- You have received the intriguing message “Unhandled Error in Silverlight Application The value cannot be undefined. Parameter name: displayText ".
A possible reason is the value “0” for a category with the type Number. Yes, yes, for you it can be quite a significant value, but due to an error in the Viewer (or some logic that I did not guess), null values for numbers cannot be used just like empty strings for string categories. Therefore, simply do not specify the value of this category for the object.
And finally, another tip. Browsers aggressively cache collections with data. Ctrl + F5 will not help you (since the amount of data can be in a few megabytes - you can only be happy with this in a real application). But if you are playing with xml to find the optimal set of filters - output the button “clear history” on the toolbar of IE or FF browsers - this will save you a lot of time. But Opera perfectly cleans all the data in its Ctrl + R.
Usually, at the end of the article you need to sum up some kind of result. Well ... This element is too good to be spoiled by minor flaws - so it was great! I really wonder if it can really simplify our search, so we are waiting for new implementations on our sites :)
Good luck and enjoy your programming!