PivotViewer series
- Building your first PivotViewer application
- Runtime PivotViewer collection creation
- PivotViewer - Working with Facets
- Handling PivotViewer events
- PivotViewer - Custom actions
- PivotViewer and MVVM
- . . .
Intro
In this tutorial about the Silverlight PivotViewer control I would like to explain how to make use of Custom Actions. Small labels are placed on top of items in the viewer and clicking them will trigger an event.
The only downside of these actions is that they aren’t fully implemented. So you’ll have to extend the PivotViewer control yourself. If you haven’t worked with the PivotViewer before, you might want to have a look at the Building your first PivotViewer application tutorial I wrote earlier first. This tutorial continues on that.
Extending the control
Start by adding a new class to a Silverlight project and naming this PivotViewerEx. Make this class inherit from PivotViewer. Create an override of the GetCustomActionsForItem method. This method is called by the PivotViewer when it is in need of some custom actions. The id of the item the user is hovering is passed to this method. You can do some filtering of the actions based on that. In this example no filtering takes place and the whole collection of custom actions is returned.
The list of custom actions is defined as property of this class. It is instantiated by the constructor.
public class PivotViewerEx:PivotViewer
{
public List<CustomAction> CustomActions { get; set; }
public PivotViewerEx()
{
CustomActions=new List<CustomAction>();
}
protected override List<CustomAction> GetCustomActionsForItem(string itemId)
{
return CustomActions;
}
}
Using the control
The extended PivotViewer control works in the same way as the original. It can be added to the XAML like below. The event that handles the clicks on the actions is added too.
<UserControl x:Class="PivotViewerCustomActions.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:PivotViewerCustomActions="clr-namespace:PivotViewerCustomActions"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<PivotViewerCustomActions:PivotViewerEx x:Name="Pivot"
ItemActionExecuted="CustomActionClicked"/>
</Grid>
</UserControl>
In the code behind, in the constructor of the page, the custom actions itself are added to the PivotViewer. The constructor of the CustomAction class takes four parameters:
- Name => is the text shown in the PivotViewer
- Icon => a URI to an image to show next to the text. You can use NULL to omit an image
- ToolTip => some text that is shown when the user hovers the mouse over the CustomAction
- Id => a unique ID to identify the action
public MainPage()
{
InitializeComponent();
Pivot.CustomActions.Add(
new CustomAction("Add to cart",
new Uri("http://localhost:49000/112_Plus_Green_32x32_72.png"),
"Add to cart","Add"));
Pivot.CustomActions.Add(
new CustomAction("Details",
new Uri("http://localhost:49000/Info.png"),
"Details","Details"));
Pivot.LoadCollection("http://localhost:49000/ElectronicsPivot.cxml",
string.Empty);
}
Handling the event
When the user clicks on the actions the CustomActionClicked event is fired. The event gets an instance of the ItemActionEventArgs class as event arguments. This class contains two properties. ItemId contains the the ID of the item the action was placed over. You can get the actual item by calling the GetItem method on the PivotViewer control with this ID.
The second property of the ItemActionEventArgs class is CustomActionId. This is the ID of the custom action that was clicked.
In the example below one of two a message boxes is shown depending on the action clicked. It won’t be hard to extend this further to your needs.
private void CustomActionClicked(object sender, ItemActionEventArgs e)
{
PivotItem item = Pivot.GetItem(e.ItemId);
if (e.CustomActionId == "Add")
{
MessageBox.Show(string.Format("Add {0} to Cart", item.Name));
if (e.CustomActionId == "Details")
{
MessageBox.Show(string.Format("Show details of {0}", item.Name));
}
}
Wrap-up
CustomActions provide a great way to add some extra functionality to the PivotViewer control. Too bad they aren’t fully implemented (yet?). The simple method shown in this tutorial uses code behind to add the actions. It would be great to be able to add these actions in XAML one day.
The next tutorial will be about using the Silverlight PivotViewer control in an MVVM application. If you want to be the first to know when it is available, you can subscribe to the RSS-Feed or follow me on twitter.


PivotViewer series
- Building your first PivotViewer application
- Runtime PivotViewer collection creation
- PivotViewer - Working with Facets
- Handling PivotViewer events
- PivotViewer - Custom actions
- PivotViewer and MVVM
- . . .
Intro
Today I would like to go into a little detail about the events used in the PivotViewer control for Silverlight. If you haven’t worked with the PivotViewer yet you might want to read the getting started tutorial I wrote earlier first.
CollectionLoadingCompleted
The CollectionLoadingCompleted event is fired when loading of the collection is completed.
CollectionLoadingFailed
The CollectionLoadingFailed event is raised when an error occurs when loading a collection. The event uses gets an instance of the CollectionErrorEventArgs class when it is fired. This class contains two properties.
The first is ErrorCode. This property is of the enum type CollectionError and contains two values: DownloadError and ParsingError.
ErrorCode equals DownloadError when there was an error downloading the collection. For example if the URL used in the LoadCollection method is wrong. The ErrorCode contains the ParsingError value when there is an issue with the .CXML file which prevents it from being parsed. For example a typing error in the .CXML.
The second property used in the CollectionErrorEventArgs class is Exception. This property contains the exception thrown by he PivotViewer control. This exception can provide very useful information when building runtime collections.
ItemDoubleClicked
This event is fired when an item in the PivotViewer is double clicked. The event is given a ItemEventArgs object. The ItemEventArgs class contains 1 property, ItemId. This string contains the ID of the items that is clicked. You can use this ID to get the whole item by calling the GetItem method on the PivotViewer control.
private void Pivot_ItemDoubleClicked(object sender, ItemEventArgs e)
{
PivotItem item = Pivot.GetItem(e.ItemId);
// insert something useful to do with the item here
// like showing a popup with more info.
}
LinkClicked
When the end-user click on a facet of the link type this event is fired by the PivotViewer control. The URL is passed to the event through the LinkEventArgs. The navigation itself isn’t performed by the PivotViewer. You’ll have to handle that yourself. The code below shows an example of that. It checks if the URL that is clicked ends with .CXML. In that case the URL is used to load a new collection. Otherwise the user will be directed to the target URL.
private void Pivot_LinkClicked(object sender, LinkEventArgs e)
{
Uri targetUrl = e.Link;
if (targetUrl.LocalPath.EndsWith(".cxml",
StringComparison.InvariantCultureIgnoreCase))
{
//If the link is to CXML, show it in this PivotViewer.
Pivot.LoadCollection(targetUrl.AbsoluteUri, string.Empty);
}
else
{
//Otherwise open the URL in a new window
HtmlPage.Window.Navigate(targetUrl, "_blank");
}
}
ItemExecutedEvent
The ItemExecutedEvent is raised when the end-user clicks on a Custom Action. Support for this isn’t fully implemented in this version of the PivotViewer control. In the next tutorial I’ll show you how to use custom actions and how they are handled using this event.
Wrap-up
There aren’t that many events in the PiverViewer control. But it’s good to know which ones are there and how to use them.
The next tutorial will be about Custom Actions. To be the first to know when it is released you can subscribe to the RSS-feed or follow me on twitter.




PivotViewer series
- Building your first PivotViewer application
- Runtime PivotViewer collection creation
- PivotViewer - Working with Facets
- Handling PivotViewer events
- PivotViewer - Custom actions
- PivotViewer and MVVM
- . . .
Intro
In this next tutorial about the Silverlight PivotViewer control I would like to give a little more depth on Facets. What are facets, and how are they used in runtime generation of collections using the PivotServerTools library.
This tutorial continues on techniques from last tutorial about runtime collection creation. If you are just getting started using the PivotViewer control, you might want to have a look at the Getting Started Tutorial first. This tutorial is centered around the methods build in the last tutorial: MakeCollection and MakeItem.
Facets
Facets are basically the properties on the PivotViewer that allow the visitor to sort and filter. Facets are also shown when viewing the details of an item.

Facets are added to the collections by calling the Collection.AddItem() method. This method takes a couple of parameters. The first is the Name of the item being added. The second is a URL. This can be used to navigate to more details about the item for example. This URL is used when clicking on the Name of the item in the details panel. Then there’s the Description of the item. This text is shown on the details panel. The fourth parameter is the image shown in the DeepZoom part of the control. The ItemImage type from the PivotServerTools. Its constructor is used, to which a URL to the image is given. All parameters after that, from the fifth on are Facets. You can add as many as you need. A call to AddItem might look something like this:
collection.AddItem(
id,
url,
description,
new ItemImage(new Uri(image)),
new Facet("String value", FacetType.Text, id),
new Facet("Integer Value", FacetType.Number, intValue),
new Facet("Double Value", FacetType.Number, doubleValue),
new Facet("Date value",FacetType.DateTime,date),
new Facet("Url Value",FacetType.Link, new FacetHyperlink("Url Value", urlValue)),
new Facet("Names", names),
new Facet("FormattedValue",formattedValue)
);
Facets are grouped in Facet Categories. Every item in the collection can contain one or more facet categories and every category can contain one or more facets. Facet categories are created when a they are used for the first time while adding items to the collection.
The PivotServerTools library is used to generate the .CXML. It uses 4 types of facets categories:Text, Number, DateTime and Link. The type of facet category determines how facets are displayed in the PivotViewer control. Each facet in the category must be of this type.
Text:
The text type is used to display anything of type string. If the type is omitted and the type can’t be determined automatically the Text type is defaulted to.
To create a facet of type text you can use its constructor with a category name, the type of facet and its tag. For example:
Facet stringFacet = new Facet("Names", FacetType.Text, name);
This might look something like this in the PivotViewer control.

Number:
This facet type is used to display numbers. It allows the end-user to make selections on ranges of this tag. This tag value can also be formatted which I’ll explain later.
Again, to create a facet of this type, use its constructor and pass in a different FacetType this time:
Facet integerFacet = new Facet("Integer Value", FacetType.Number, intValue);
Facet doubleFacet = new Facet("Double Value", FacetType.Number, doubleValue);

DateTime:
Dates are displayed like in the image below. You can select a date by era, the actual value or select a custom range.
The date facets are added the same way as numbers or text, but with a different FacetType.
Facet dateFacet = new Facet("Date value",FacetType.DateTime, date);
Link:
Hyperlinks are not shown in the filter list. Only the name given to the URL is shown in the details list. Clicking on a link does not navigate by default. You’ll have to implement the navigate yourself. An event is fired when an item on the details panel is clicked though.
To create a facet of type link you can use its constructor again. Only the third parameter is different this time. It takes a value of type FacetHyperLink. The type uses a description and a URL together. In the code below both are passed into the constructor of FacetHyperLink. Both parameters are strings.
Facet linkFacet = new Facet("Url Value", FacetType.Link,
new FacetHyperlink("Displayed Name", urlValue));
One last thing to notices about adding items to the collection. As I mentioned earlier, every facet category can be used zero or more times. The constructor of Facets takes one or more values for a value for each tag. You could, for example, add an array of strings to a category at once just by passing that array to the constructor. All values will be shown in that category on the details panel.
string[] myNames = {"Timmy Kokke", "Sorskoot"};
Facet namesFacet = new Facet("My Names",FacetType.Text, names );
More on categories
After the items are added to the collection you can fine-tune the categories a little further. Often it is necessary to make facet categories visible in only the details panel or enable filtering for a particular category but disable text search on them. The Collection class has a method to set these properties.
The SetFacetDisplay method takes the name of the category and 3 booleans. The first of the three booleans indicated whether or not the category is shown in the list of filters. The second enables or disables the category showing up in de info panel. When the last is set to false the category is excluded from the text search.
Here are a few examples.
collection.SetFacetDisplay("Integer Value", true, false, false);
collection.SetFacetDisplay("Double Value", false, true, false);
collection.SetFacetDisplay("Names", true, true, false);
The Integer Value category is shown in the list of filters, but hidden from the info panel and the text search. The Double Value category is hidden from the filters and the text search, but is visible on the info panel. The Names category is visible in both filters and info panel, but isn’t used for text search.
The Collection class has one other method of interest concerning facets. The SetFacetFormat is used to set format of a category in which it is displayed. It uses standard .NET string formatting. For example, to display a double as a floating point with 3 decimals you can use the following code:
collection.SetFacetFormat("FormattedValue", "F3");
Wrap-up
The code that goes along with this tutorial can be downloaded here. The next tutorial will be about the events of the PivotViewer control. To be the first to know when it is released you can subscribe to the RSS-feed or follow me on twitter.
Technorati Tags: Silverlight,PivotViewer




PivotViewer series
- Building your first PivotViewer application
- Runtime PivotViewer collection creation
- PivotViewer - Working with Facets
- Handling PivotViewer events
- PivotViewer - Custom actions
- PivotViewer and MVVM
- . . .
Intro
Today I would like to show you how you can consume web services in the PivotViewer control for Silverlight and build a collection at runtime. This tutorial is based on examples found on www.getpivot.com and the getting started tutorial I posted earlier this week. This tutorial used the previous as a starting point, so if you haven’t read that you probably want to do that first. The only difference is that I named the project PivotViewerDynamic this time.
The PivotViewer control loads a collection by reading an .CXML file. To get the PivotViewer to load a generated collection HTTP handlers are used to redirect the request for an .CXML file to custom code. This code, the Collection Factory, returns the collection in .CXML format. Requests for the DeepZoom images used in the collection are also redirected to custom code is capable of generating images on the fly or load them from the web.
Building a Factory
The factory class that will be building the collection is based on a class that can be found in one of the examples on www.getpivot.com. You can download this example here. Add the PivotServerTools project from this example to the project created in the Getting Started tutorial. And add a reference to the PivotServerTools project from the Web project. It is also include in the sample code for this tutorial.
To be able to use the factory a custom HTTP handler needs to be build. This sounds more complex than it is.
Start by adding a new class to the Web project and name this class CxmlHandler. Make this class implement the IHttpHandler interface. This will give you one method, ProcessRequest, and one property, IsReusable. Add one line of code to the ProcessRequest() method as shown below. The PivotHttpHandlers.ServceCxml() method will look for factories and returns the collection in .CXML format. Don’t forget to resolve a using to the PivotServerTools namespace.
public class CxmlHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
PivotHttpHandlers.ServeCxml(context);
}
public bool IsReusable
{
get { return true; }
}
}
To get the HTTP handler to work it has to be configured in Web.Config. To do this add the code below.
<system.webServer>
<handlers>
<add name="CXML" path="*.cxml" verb="GET"
type="PivotViewerDynamic.Web.CxmlHandler"/>
</handlers>
</system.webServer>
It also has to be defined in the system.web section of the config file. Add the code below to the system.web section
<httpHandlers>
<add path="*.cxml" verb="GET" type="PivotViewerDynamic.Web.CxmlHandler"/>
</httpHandlers>
This makes sure that every request for a .CXML file is redirected to the PivotViewerDynamic.Web.CxmlHandler class.
It’s time to add the actual factory class now. Add a new class to the Web project and name this DemoCollectionFactory. Make this class implement the base class CollectionFactoryBase and make sure you resolve the PivotServerTools namespace. Only the MakeCollection method is overridden from the base class. We’ll add the functionality of this method later.
Add a constructor to this class to set the name of the factory. This name is going to correspond with the name of the .CXML file requested. The constructor will look something like this now:
public DemoCollectionFactory()
{
this.Name = "Demo";
}
The collection factory is ready to use now. Lets load it from the Silverlight part of the application.
The PivotViewer control should already be there if you’re using the code from the first tutorial. If not, add the control like below:
<UserControl x:Class="PivotViewerDynamic.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Pivot="clr-namespace:System.Windows.Pivot;assembly=System.Windows.Pivot">
<Grid x:Name="LayoutRoot" Background="White">
<Pivot:PivotViewer x:Name="Pivot"/>
</Grid>
</UserControl>
Add or change the Pivot.LoadCollection method in the code behind MainPage.xaml.cs to
Pivot.LoadCollection("http://localhost:49000/demo.cxml",string.Empty);
This examples assumes the Web project is running on port 49000. If not, go to the Project properties and on the Web tab set Specific Port, in this case 49000.

Add a breakpoint to the MakeCollection() method in the factory to make sure it works. Now hit F5 to compile and run.
Filling the Collection
If all went well you should have got the application running, although it doesn’t do much yet. Let us fill the collection.
To fill the collection an .XML file is downloaded from the server and fed to the collection.
public override Collection MakeCollection(
CollectionRequestContext context)
{
string data;
using (var web = new WebClient())
{
data = web.DownloadString(
"http://localhost:49000/DemoData.xml");
}
Next, a string reader is created. Which in turn is passed to the XElement.Load() method which parses the XML.
var reader = new StringReader(data);
XElement root = XElement.Load(reader);
A collection has to be instantiated before it can be filled with data. For each DemoData element in the parsed XML the MakeItem() method is called. This method is described a little later. It fills the collection with data from the the XML entries. Before the collection will be returned, its name is set.
var collection = new Collection();
foreach (XElement entry in root.Elements("DemoData"))
{
MakeItem(collection, entry);
}
collection.Name = "Demo Collection";
return collection;
}
The MakeItem() method takes the instance of the collection and an entry from the XML data. It extracts three values, Id, Value1 and Description. These are passed into the AddItem() method. This method takes 5 parameters. The first is the Name of the item. The second is for a URL. The third is a description of the item. The fourth an image. If the image is omitted an image will be generated. The last parameter is a collection of Facets. Facets are the properties of the collection. You filter and sort the collection by facets. The PivotViewer control decides the best way to show them in the filter section. There a five types of facets: String, LongString, Number, DateTime and Link. In this case we let the control figure out what type to use.
MakeItem:
private void MakeItem(Collection collection, XElement entry)
{
int id= int.Parse(entry.Element("Id").Value);
double value = double.Parse(entry.Element("Value1").Value);
string description = entry.Element("Description").Value;
collection.AddItem(
id.ToString(),
null,
description,
null,
new Facet("Value",value));
}
To get the runtime generated collection to show the right images, HTTP handlers have to be added for the DeepZoom images.
Add empty .cs file named DeepZoomHandlers.cs and place the four handlers below in there: DeepZoomCollection(.DZC), DeepZoomImage(.DZI) and two paths to images to handle the loading of images by code. All these handlers call methods in the PivotServerTools in the same way the CxmlHandler does.
using System.Web;
using PivotServerTools;
namespace PivotViewerDynamic.Web
{
public class DzcHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
PivotHttpHandlers.ServeDzc(context);
}
public bool IsReusable
{
get { return true; }
}
}
public class ImageTileHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
PivotHttpHandlers.ServeImageTile(context);
}
public bool IsReusable
{
get { return true; }
}
}
public class DziHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
PivotHttpHandlers.ServeDzi(context);
}
public bool IsReusable
{
get { return true; }
}
}
public class DeepZoomImageHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
PivotHttpHandlers.ServeDeepZoomImage(context);
}
public bool IsReusable
{
get { return true; }
}
}
}
Add these handlers to the web.config too. Add the lines below to the HttpHandler section in system.web.
<add path="*.dzc" verb="GET"
type="PivotViewerDynamic.Web.DzcHandler"/>
<add path="*.dzi" verb="GET"
type="PivotViewerDynamic.Web.DziHandler"/>
<add path="*/dzi/*_files/*/*_*.jpg" verb="GET"
type="PivotViewerDynamic.Web.DeepZoomImageHandler"/>
<add path="*_files/*/*_*.jpg" verb="GET"
type="PivotViewerDynamic.Web.ImageTileHandler"/>
Add the lines below to the Handlers section in System.WebServer:
<add name="DZC" path="*.dzc" verb="GET"
type="PivotViewerDynamic.Web.DzcHandler"/>
<add name="DZI" path="*.dzi" verb="GET"
type="PivotViewerDynamic.Web.DziHandler"/>
<add name="DeepZoomImage" path="*/dzi/*_files/*/*_*.jpg"
verb="GET" type="PivotViewerDynamic.Web.DeepZoomImageHandler"/>
<add name="ImageTile" path="*_files/*/*_*.jpg"
verb="GET" type="PivotViewerDynamic.Web.ImageTileHandler"/>
You should be able to run the application now.

Wrap-up
In this example I used a very simple .XML file. It won’t be hard to change the code to consume external web services. As long as there are items return that can contain sets of data it can be shown in the PivotViewer, like Rss feeds, Twitter and even OData.
In this first version of the PivotViewer it is not possible to style the control, but you can do other fun stuff with it. You can expect more tutorials on the PivotViewer in the future. To be the first to know about that you can subscribe to the RSS-feed or follow me on twitter.
You can download the code for this tutorial here.




PivotViewer series
- Building your first PivotViewer application
- Runtime PivotViewer collection creation
- PivotViewer - Working with Facets
- Handling PivotViewer events
- PivotViewer - Custom actions
- PivotViewer and MVVM
- . . .
Intro
If you haven’t had a chance to look at the new PivotViewer control for Silverlight, have a look here or here. The PivotViewer enables visitor of you website to search large amounts of data very easily. The control takes a lot work out of your hands. Basically you tell it to load a collection and the PivotViewer takes care of everything else. Like adding controls to enter search and sort criteria. It uses DeepZoom to show large amounts of images and animate between states.
Getting started
Before you can start coding you have download the control itself. The Silverlight control can be downloaded from the PivotViewer section on Silverlight.net. You also need the Silverlight Toolkit which can be found here.
Your first PivotViewer
To get your first PivotViewer control up and running create a new Silverlight project in Visual Studio and add references to all 5 PivotViewer assemblies to the Silverlight project. These assemblies can be found in C:\Program Files\Microsoft SDKs\Silverlight\v4.0\PivotViewer\Jun10\Bin or C:\Program Files (x86)\Microsoft SDKs\Silverlight\v4.0\PivotViewer\Jun10\Bin on 64bit system.
In MainPage.xaml add an xml namespace definition for the System.Windows.Pivot namespace and add the control to the LayoutRoot grid.
<UserControl x:Class="PivotViewerGettingStarted.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Pivot="clr-namespace:System.Windows.Pivot;assembly=System.Windows.Pivot">
<Grid x:Name="LayoutRoot" Background="White">
<Pivot:PivotViewer x:Name="Pivot"/>
</Grid>
</UserControl>
Getting data in the PivotViewer control has to be done in CodeBehind. The PivotViewer contains a method LoadCollection which takes an URL to a .CXML file. This file can be stored anywhere on the web and can be accessed as log as there is a valid ClientAccessPolicy.xml file available. For demonstration purposes there a couple of collections available on the GetPivot.com site (at the end of this tutorials I’ve added a list of these). I’ve used the AMG Movies Collection in this case.
The LoadCollection method also needs a value the state. Often this value is set to string.Empty.
public MainPage()
{
InitializeComponent();
Pivot.LoadCollection(
"http://content.getpivot.com/collections/amg/Top_Movies.cxml"
, string.Empty);
}
Take a look at the control running here.
What’s next
While using the collection on GetPivot.com can be vary useful for demonstrations or learning how to develop with the PivotViewer, you won’t use these collection in a real application. You will have to create a collection of your own. Have a look at this section of GetPivot.com about the Excel extension to create a collection.
Another way to create collection is to let your program take control and build collection runtime. I will explain this in my next tutorial.
If you can’t wait and want to learn more, read the developer section on www.getpivot.com
Other example sources
On the GetPivot.com site there are a few more .CXML collection to try in your applications:
Dog Breeds
Sports Illustrated Covers
AMG Movies
NFL Teams & Athletes
Wikipedia Collection






Intro
Often extensions for Expression Blend need to store some global variables. Why not use the mechanisms Blend itself offers? I’d like to show you how to add a custom options page to the options dialog.
I’ve started the example project by creating a new C# WPF Custom Control Library project and naming it ExtendingBlendOptionsTutorial. The details on how to create a new Blend Extension can be found here. You need to make sure the Microsoft.Expression.Extensibility and Microsoft.Expression.Framework assemblies are referenced in your project. Both can be found in the Expression Blend installation folder on your machine.
The architectural design is taken from the existing option pages that are used by Blend. Every existing page uses a '’…Page’ , a ‘…Control’ which is contains the xaml for the dialog and a ‘…Model’. The Model is bound to the Control. The example in this tutorial follows the same pattern.
IPackage Implementation
Let’s start at the beginning. When Blend is started, it loads the extensions using MEF. Therefore the extension has to be an implementation of the IPackage interface and has to be decorated with an Export attribute.

The code is pretty simple. From the IServices provided by Blend, an instance of the IOptionsDialogService is requested. This services contain a collection of all option pages. Every options page is an implementation of IOptionsPage.
In this case, a new TutorialOptionsPage is created in the Load method. A new TutorialOptionsModel is passed into this. After that the TutorialOptionsPage is added to the list of option pages.
[Export(typeof(IPackage))]
public class OptionsTutorialPackage:IPackage
{
public void Load(IServices services)
{
IOptionsDialogService optionsDialogService =
services.GetService<IOptionsDialogService>();
TutorialOptionsPage optionsPage =
new TutorialOptionsPage(new TutorialOptionsModel(services));
optionsDialogService.OptionsPages.Add(optionsPage);
}
public void Unload()
{
}
}
The Options Page
The TutorialOptionPage is basically an implementation of the IOptionPage interface.
Properties:
- Content - contains a framework element containing the view of the options page. It should contain input elements to set the configuration options.
- Title - contains the title of the options page. It is shown in the list on the left of the options dialog.
- Name - contains the internal name of the page.
Methods:
- Cancel - is called when the user hits the cancel button of the options dialog.
- Commit - this is called when the user hits the Ok button.
- Load - is called when Blend starts.
First, let’s have a look at the declarations and the constructor. The TutorialOptionPage class has to implement the IOptionsPage interface to work. This interface can be found in the Microsoft.Expression.Framework.Configuration namespace. References to the TutorialOptionsControl, and the TutorialOptionsModel, are kept. As well as a reference to the IConfigurationObject interface.
The constructor takes an instance of TutorialOptionsModel and stores it.
public class TutorialOptionsPage:IOptionsPage
{
private TutorialOptionsControl tutorialOptionsControl;
private TutorialOptionsModel tutorialOptionsModel;
private IConfigurationObject configurationObject;
public TutorialOptionsPage(TutorialOptionsModel model)
{
tutorialOptionsModel = model;
}
The implementations of the Title and Name properties is very simple. They both just return a string.
public string Title
{
get { return "TutorialOptionsTitle"; }
}
public string Name
{
get { return "TutorialOptionsName"; }
}
The Content property returns an instance of the TutorialOptionsControl, the UI of the options page. It needs an instance of the IConfigurationObject to load the data for the model. This interface is passed to the Load method which I’ll describe in a second.
If the model isn’t loaded, which happens when the changes in the options dialog are cancelled, a new one has to be instantiated. The configuration data has to loaded as well in this case.
The Load method on the model is called. After this, it is passed to the constructor of the TutorialOptionsControl where it will be bound to the UI.
public object Content
{
get
{
if (this.tutorialOptionsModel == null)
{
this.tutorialOptionsModel = new TutorialOptionsModel();
this.tutorialOptionsModel.Load(configurationObject);
}
if (this.tutorialOptionsControl == null)
{
this.tutorialOptionsControl =
new TutorialOptionsControl(this.tutorialOptionsModel);
}
return this.tutorialOptionsControl;
}
}
Right, the Load method of the TutorialOptionsPage class. It takes the IConfigurationObject interface as a parameter, which is provided by Blend. It is stored in the class to use it again later. The model is loaded by using the IConfigurationObject.
public void Load(IConfigurationObject value)
{
configurationObject = value;
this.tutorialOptionsModel.Load(this.configurationObject);
}
The Cancel method is called when the user hits the “Cancel” button on the options dialog. Both the TutorialOptionsControl and the TutorialOptionsModel are set to null to make sure they will be reloaded the next time the options dialog is opened.
public void Cancel()
{
this.tutorialOptionsControl = null;
this.tutorialOptionsModel = null;
}
The Commit method is called when the user hits the "Ok” button on the options dialog to save the settings. First the configurationObject has to be cleared to remove any unwanted settings the might be left over. The Save method on the model is called and the configurationObject is giving to it.
Last both the TutorialOptionsControl and the TutorialOptionsModel are reset to be reloaded the next time they’re needed.
public void Commit()
{
if(this.tutorialOptionsModel!=null)
{
this.configurationObject.Clear();
tutorialOptionsModel.Save(configurationObject);
this.tutorialOptionsControl = null;
this.tutorialOptionsModel = null;
}
}
The Model
In this example, the model contains only two properties, two strings. To make sure the UI will be updated correctly, the INotifyPropertyChanged interface is implemented.
Saving and loading of the properties is done in the Load and Save methods. Both methods make use of an IConfigurationObject. The properties are saved using the SetProperty method from the IConfigurationObject interface. To load the properties, the GetProperty method is called for each property. The same keys are used as with saving and the returned objects are cast to the correct type.
public class TutorialOptionsModel : INotifyPropertyChanged
{
private string _value1;
public string Value1
{
get { return _value1; }
set
{
_value1 = value;
InvokePropertyChanged("Value1");
}
}
private string _value2;
public string Value2
{
get { return _value2; }
set
{
_value2 = value;
InvokePropertyChanged("Value2");
}
}
public void Save(IConfigurationObject configurationObject)
{
configurationObject.SetProperty("OptionsTutorialValue1", this.Value1);
configurationObject.SetProperty("OptionsTutorialValue2", this.Value2);
}
public void Load(IConfigurationObject configurationObject)
{
Value1 =
configurationObject.GetProperty("OptionsTutorialValue1") as string;
Value2 =
configurationObject.GetProperty("OptionsTutorialValue2") as string;
}
public event PropertyChangedEventHandler PropertyChanged;
public void InvokePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
In an actual extension, the model can be used in other parts of the extension to make the configuration available for other classes. Just make sure you call the Load method.
User interface
The user interface for the Options Dialog is just XAML. In this example I have created a WPF UserControl with two textboxes to let the user enter some text. Both values are stored in Blend's configuration files. The textboxes are bound to the two properties of the model.

The XAML that is used to create this UI:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="48" />
<RowDefinition Height="48" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="124" />
<ColumnDefinition Width="176*" />
</Grid.ColumnDefinitions>
<TextBox Margin="4"
VerticalAlignment="Center"
Grid.Column="1"
Text="{Binding Value1}" />
<Label Content="Value 1:"
HorizontalAlignment="Right"
VerticalAlignment="Center" />
<TextBox Margin="4,12"
Grid.Column="1"
Grid.Row="1"
Text="{Binding Value2}"/>
<Label Content="Value 2:"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Grid.Row="1" />
</Grid>
The data context of this UserControl needs to be set to the instance of TutorialOptionsModel. This is done through the constructor of the control.
public partial class TutorialOptionsControl : UserControl
{
public TutorialOptionsControl(TutorialOptionsModel tutorialOptionsModel)
{
InitializeComponent();
this.DataContext = tutorialOptionsModel;
}
}
After compiling and starting the options page should look something like this now:

Classes and Interfaces
Here are the diagrams of the classes and interfaces used in the tutorial.


Sourcecode
The code for the project can be downloaded here.


Intro
One of the new additions in Expression Blend 4 is the Silverlight Databound Application Project template. I use that often when starting a new MVVM project. The template creates View and ViewModel folders and provides a good starting point for Model-View-ViewModel applications. The only downside is that this template is only available in Expression Blend and not in Visual Studio 2010.
I’ve exported the project to a Visual Studio template to be able to use it in VS2010 too.
Download
The template can be downloaded here.
Installation
Just place the .zip in ??\Documents\Visual Studio 2010\Templates\ProjectTemplates\Visual C#\Silverlight
Do not extract. It should work in VS2010 now.
Intro
When running Silverlight 4 out of the browser it could become handy to know that the application is being closed. In case of my open source demo application SilverAmp (http://SilverAmp.CodePlex.com) I wanted to notify the user the application is being closed when music is still playing.
Catching the event
In Silverlight 4 a new event has been added to the System.Window class. This event is raised when the application is being closed. Closed in any way: by the user hitting F4; by the user clicking on the right-top cross; by a calling close on the application from within code or even when windows is shut down.
The great thing about handling this event is that you can cancel it. In the example below the closing event is handled and the user is asked if he wants to exit the application. The application uses a MediaPlayer to play media which is named _internalPlayer. If the currentState of the player is playing than a message box is shown. If the user chooses not to quit, the closing is canceled by setting the Cancel property of the ClosingEventArgs to true.
public MainPage()
{
InitializeComponent();
Application.Current.MainWindow.Closing += MainWindow_Closing;
}
void MainWindow_Closing(object sender, System.ComponentModel.ClosingEventArgs e)
{
if (_internalPlayer.CurrentState == MediaElementState.Playing)
{
if (MessageBox.Show("Music is playing, exit application?",
"Exit",
MessageBoxButton.OKCancel) == MessageBoxResult.Cancel)
{
e.Cancel = true;
}
}
}
One last note: you might want to add a check if the application is running out-of-browser. Using the closing event in browser causes an exception.
Technorati Tags:
Silverlight,
OOB
Since today XamlResource.com is officially in beta. Its purpose is to create a platform to find and share resources for Silverlight and WPF, resources in the form of Xaml. Have a look around and if you run into issues, please let us know at xaml@hotmail.nl.
Beta 1:
In Beta 1 only a few of the final categories are supported:
- Colors; Resources of type SolidColorBrush
- Gradients; Resources of type GradientBrush
- Color sets; 2 to 5 resources of type SolidColorBrush
- Vectors; Resources of type StreamGeometry
This list will be extended with Styles, Themes, Templates and Shaders.
Future plans:
- Adding tags and searching by them.
- Access to the site from within Expression Blend
- Client side validation of entered xaml using Silverlight
- Automatic generation of preview image
- Download multiple resources at once in one ResourceDictionary
- An rss feed for news items
If you have requests for features you can let them know by using http://XamlResource.uservoice.com. For anything else, send an email to xaml@hotmail.nl.
To keep up to date, follow us at http://twitter.com/XamlResource

Intro
Today I would like to explain something about customizing the window chrome in Silverlight 4 OOB. For an example of customizing the window have a look at my open source demo application SilverAmp which is available on http://SilverAmp.CodePlex.com.
Choosing style
Running the application without the default window chrome requires running out-of-browser with elevated trust. How to set elevated trust is explained in this earlier post. To set the window style, go to the Out-Of-Browser settings on the Application tab in the Project Settings. At the bottom there’s a dropdown list where you can select your preferred style.
- Default shows the window as you’re used to, with the normal window style.
- No Border shows a borderless window
- Borderless Round Corners shows a borderless window too, but with rounded corners.
In the case of SilverAmp I choose to No Border.
Default Windowing Events
In both borderless styles you’ll have to handle the default windowing events yourself. Maximizing, minimizing, moving and resizing are simple calls into Application.Current.MainWindow.
For example:
private void TitleBar_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (Application.Current.IsRunningOutOfBrowser)
{
Application.Current.MainWindow.DragMove();
}
}
private void CloseButton_Click(object sender, RoutedEventArgs e)
{
if (Application.Current.IsRunningOutOfBrowser)
{
Application.Current.MainWindow.Close();
}
}
private void MinimizeButton_Click(object sender, RoutedEventArgs e)
{
if (Application.Current.IsRunningOutOfBrowser)
{
Application.Current.MainWindow.WindowState = WindowState.Minimized;
}
}
The first event handler handles the MouseLeftButtonDown event on a rectangle representing the title bar of the application.
On this same title bar there are two buttons: Close and Minimize. Both buttons got an Click event handler.
All event handlers perform a check to see if the application is running out-of-browser. Calling these methods inside the browser will cause an exception.
Technorati Tags:
Silverlight,
OOB