Silverlight 5 Beta was announced at MIX11 yesterday. This blog post is an overview of Silverlight 5 development tools. To get started, download following components:
SL4 development requires VS2010 or VWD2010 RTM and SL4Tools, and optionally Blend 4. VS2010 SP1 has SL4 support built in, so SL4Tools is not needed if you’ve already upgraded to VS2010 SP1. SL5 development requires VS2010 or VWD2010 SP1 and SL5Tools, and optionally Blend Preview for Silverlight 5.
Once installed, you can create SL5 projects like you used to with previous versions of SL:
SL5 projects can reference assemblies built against early versions of Silverlight. Below screenshot shows a SL5 project using SL4 SDK via Project->Add Reference…–>Browse:
Please notice the HintPath and assembly version (Btw, SL5 increased assembly version from 2.0.5.0 to 5.0.5.0).
You can also upgrade existing SL4 projects to target SL5:
The upgrade changes <ProjectGuid> and <TargetFrameworkVersion> in .csproj, as well as upgrading all SDK references to SL5’s.
Binding Debugging
A popular new feature in SL5Tools is xaml binding debugging:
Blend Preview for Silverlight 5
Optionally, you can also install Blend Preview for Silverlight 5, which is basically Blend 4 with SL5 support:
And you can use both VS and Blend on the same SL5 project and switch between them:
Troubleshoot & Uninstall
VS2010 SP1, SL5Tools and Blend Preview install all take a long time, so please be patient. If you run into install issues, you may want to take a look at install logs in %temp% directory, and attach those logs when you report install issues to Microsoft:
C:\Users\ningz\AppData\Local\Temp>dir /b /o-d *silver* Silverlight 5 Beta Tools for Visual Studio 2010 SP1_20110413_220121704.html Silverlight 5 Beta Tools for Visual Studio 2010 SP1_20110413_220121704-MSI_RiaServices.msi.txt Silverlight 5 Beta Tools for Visual Studio 2010 SP1_20110413_220121704-MSI_silverlight_sdk.msi.txt Silverlight0.log
To uninstall Silverlight 5 tools, use control panel to uninstall each component individually:
SL5 runtime, SDK, RIA Services, Blend Preview
And Update to VS2010 (KB2502836) (please click “View installed updates” to see below)
After helping a few customers with Silverlight install issues, I think it may be helpful to publish a Silverlight deployment troubleshooting guide and keep it up-to-date, so here you go.
Troubleshooting Steps
Is Silverlight installed? on Windows, make sure “Microsoft Silverlight” is in Control Panel –> Programs and Features: On Mac, make sure /Library/Internet Plug-Ins/Silverlight.plugin is there. If Silverlight isn’t installed, you can install the latest version from http://www.silverlight.net or http://www.microsoft.com/silverlight.
Do you have administrative privilege on the machine? You will need local administrative privilege to install Silverlight.
Is Silverlight enabled? For Internet Explorer, select menu item Tools –> Manage Add-ons, make sure Microsoft Silverlight is enabled for all web sites: For Firefox, select menu item Tools –> Add-ons, click Plugins tab, make sure Silverlight Plug-In is enabled:
Is the issue site specific? try http://silverlight.net: if you see the showcase Silverlight application on the top right of the page, then your issue is likely to be site specific, please report the issue to the site owner. O/w, please click the Forums tab at http://silverlight.net page, search and/or report the issue there.
Is the issue browser specific? try open the page in a different browser (IE/Firefox/Chrome on Windows, Safari/Firefox/Chrome on Mac) and see whether the issue repros. If it doesn’t repro, it is likely to be a browser specific configuration issue. Again, it may help to search http://forums.silverlight.net to see whether this is a known issue; and if not, report it.
Issue: a few people get prompted repeatedly to install Silverlight while visiting web sites like nbcolympics.com.
Solution: if you have old version of Webshots Toolbar or Kiwee Toolbar from American Greetings, you should upgrade to latest version from their web sites.
Details:
A few people trying to view Olympics videos from www.nbcolympics.com got prompted to install Silverlight, so they did and then hit F5; the page somehow prompted them to install Silverlight again, so they did again; but this time Silverlight install fails with a telltale error code 1514: Silverlight is already installed; if you want to reinstall, you need to uninstall first. So they uninstall and reinstall, but that didn’t help: they got prompted to install Silverlight again.
After quick investigation, I’ve found a common cause of old version of Webshots or Kiwee installed on those users’ machines. To check, you can find Webshots from Control Panel –> Programs and Features:
or on disk:
The fix is to go to www.webshots.com and upgrade to the latest version (3.1.5.7617 for now):
then you should be able to watch Olympics video just fine with Webshots toolbar enabled as well:
I will publish another blog post with common setup issues and solutions for Silverlight.
Disclaimer:
I am publishing this blog in a hurry to help those with trouble viewing Olympics video, so I may not get all facts right. I’d appreciate all feedback/correction/suggestion.
This is my personal blog. What I say in this blog is my opinion only. It doesn’t represent Microsoft or any other organization.
If you write Silverlight controls, you should consider writing design time assemblies for your controls too, for two simple reasons:
developer productivity: try to imagine Silverlight development without tools like Visual Studio or Blend! For custom controls, you may need to provide much of the design time experience for your controls in Visual Studio or Blend yourself.
designers: XAML and tools like Blend enable developers and designers work together. A key design criteria for Silverlight controls is to make sure designers can use them without writing a single line of code.
Design time experience usually includes (but not limited to) the following:
Metadata for property window, like category, infotip, property editor, binding etc.
Metadata for design surface, like initializer, adorner, context menu, adapters etc.
Toolbox integration, like icons, control registration
intellisense for code editor
Except intellisense (please see Add Rich Intellisense for Your Silverlight Controls) and control registration (please see Register Silverlight Controls with visual Studio and Blend), above design time experience are usually delivered through design time assemblies. Below I will discuss various approaches of delivering design time experiences, in increasing complexity and flexibility, and gradually introduce pieces of the naming convention of design time assemblies.
Runtime Assembly Only
The simplest way to deliver design time experience is to package design time code into the runtime assemblies, especially when design time metadata are meaningful at runtime too, like TypeConverterAttribute.
The pros and cons of this approach:
Pro: simple
no separate design time assemblies, simpler setup
design time attributes are specified directly on the runtime code, easier to maintain
Con: tight coupling of runtime and design time code
perf degradation because of useless design time code at runtime
design time dependencies (like MWDs and other VS/Blend assemblies) get dragged into runtime unnecessarily
can’t service runtime or design time independently
can’t support multiple designers (like both VS2008/Blend2 and VS2010/Blend3)
So this approach is highly discouraged, unless there is strong justification for it.
Shared Design Time Assembly
So the revolutionary step forward is to decouple design time and runtime code, release and service them with separate assemblies. This opens up all kinds of possibilities. Of course, we need a way to link design time assemblies to their corresponding runtime assemblies, without introducing any unnecessary dependency or perf degradation to runtime assemblies. Hence the naming convention: if a runtime assembly Foo.dll is referenced in a Silverlight project, the designer (like Visual Studio and Blend) will first try to load design time information like icons (via another naming convention, see How to Add an Toolbox Icon for Your Silverlight Control) and design time metadata (via interface, like IRegisterMetadata for VS2008 and Blend2, or IProvideAttributeTable for VS2010 and Blend3. Please see How to Write Silverlight Design Time for All Designers: Visual Studio 2008, Blend 2; Blend 3, and Visual Studio 2010) from the runtime assembly; it will then look for a design time assembly by the name Foo.Design.dll in the same directory as Foo.dll; if found, the designer will try to load design time information from Foo.Design.dll as well.
Designer Specific Design Time Assembly
Visual Studio is mostly for developers, while Blend is mostly for designers, so they have difference requirements for design time experiences. Putting all design time code in one shared design time assembly introduces tight coupling among designers. So the naming convention is enhanced: for runtime assembly Foo.dll, there is a shared design time assembly Foo.Design.dll that’s loaded by all designers; each designer will also try to load its own design time assemblies, like Foo.VisualStudio.Design.dll for Visual Studio, and Foo.Expression.Design.dll for Blend. The designer specific design time assembly is loaded after the shared design time assembly. Third party designers can define their own designer specific design time assembly.
Design Sub Folder
So to support both Visual Studio and Blend, each runtime assembly has three design time assemblies, in the same directory, and a package (like Silverlight SDK or Silverlight Toolkit) usually contains several runtime assemblies. So the directory gets a bit crowded. A minor improvement is to put the design time assemblies under a Design subfolder. So the naming convention is further enhanced: if a designer (like Visual Studio or Blend) can’t find corresponding design time assemblies in the same directory as a runtime assembly, it will look for them in the Design subfolder, if it exists.
Support Multiple Versions of MWDs
Design time are built on top of designer extensibility framework, which consists of several dlls like Microsoft.Windows.Design.Extensibility.dll and Microsoft.Windows.Design.Interaction.dll. We usually call them collectively as MWDs. To make life more interesting, sometimes we have to introduce breaking changes to the extensibility framework, like VS2008 and Blend2 use MWD version 3.5, VS2010 and Blend3 use MWD version 4.0, and they are incompatible. So if you have a runtime assembly Foo.dll, and you want your users to be able to develop against it with both VS2008 and VS2010, you have to provide two sets of design time assemblies: one set built against v3.5 MWDs and used by VS2008, and another set built against v4.0 MWD and used by VS2010. The two sets of design time assemblies probably have a lot of code in common, while the one for VS2010 may have some new code to leverage the new functionalities exposed by VS2010. Since design time assemblies are loaded by name and you can’t have two files with the same name, so the naming convention is enhanced yet again:
for a runtime assembly Foo.dll, the shared design time assembly is named Foo.Design*.dll, the Visual Studio specific design time assembly is named Foo.VisualStudio.Design*.dll, and the Blend specific design time assembly is named Foo.Expression.Design*.dll, where * can be zero or more valid characters for file names. When a designer (like Visual Studio or Blend) tries to load a design time assembly and several fit the naming convention, zero or one will be loaded:
If the MWD version referenced by the design-time assembly has a different major version number than the designer’s MWD version, then the design-time assembly will not load and is bypassed.
If more than one design-time assembly is compatible with the designer’s MWD version, the Designer loads the one compiled against the highest MWD version that is less than or equal to the designer’s MWD version.
To complicate life further, since WPF and Silverlight are so awfully similar, you may be tempted to try to write it once and run with both WPF and Silverlight. You are not alone. There are many articles on how to share source code and/or binaries across Silverlight and WPF. We’d like to do that for design time assemblies too. One approach is to make most of the design time assemblies platform agnostic, and limit platform specific (WPF or Silverlight) code and references to a small platform specific assembly. Please see Extensibility Series – WPF & Silverlight Design-Time Code Sharing – Part I for more information on this.
Last One Wins
The same design time metadata for a class or its member can be specified multiple times in multiple design time assemblies, which allows the shared design time assembly to specific the default/common behavior and then designer specific design time assemblies to override it if necessary. The same design time metadata can also be specified multiple times within a single design time assembly (please see Design Time Feature Implementation in Silverlight Toolkit as an example, where DescriptionAttribute for a class or its property can be added by AddDescriptions, AddAttributes and AddTables methods). So we need to know which metadata wins. The simplest and most logic design is that last one wins. This is mostly true but not always. Sometimes the result is un-deterministic when the same design time metadata is specified several times but with different values.
Feedback
Devil is in the details! Feedbacks are always appreciated. Please let me know what issues you run into, what requests/improvements you’d like to make, for both design times experience and designer extensibility framework. Thanks!
Drag and drop is a common UX paradigm and a top requested feature. In Silverlight 4 Beta, we introduced a basic set of API to enable the most common scenario of dragging pictures files and dropping them to Silverlight applications, and we designed the API to allow us to expose more drag and drop functionalities down the road without API change, hopefully.
AllowDrop: this is dependency property, indicating whether an element is a drop target.
DragEnter, DragLeave, DragOver & Drop: these are routed events. They bubble up, and fire only on elements with AllowDrop set to true.
OnDragEnter, OnDragLeave, OnDragOver & OnDrop: these are protected virtual functions for subclasses to override.
DragEventArgs: this class allows drop target event handlers or method overrides to access the data being dragged or dropped.
Usage
There are primarily two ways to use Silverlight’s drag and drop API:
Silverlight applications can handle those drop target events and process the files dropped in the event handlers.
Silverlight controls can override those drop target virtual functions to process the data being dragged and dropped, and enable themselves to be drop targets.
Limitations
The drag and drop functionality shipped in Silverlight 4 Beta only enables the most common scenario: Silverlight plugin as a file drop target. Please notice the following limitations with current implementation:
there is no drop source support (QueryContinueDrag & GiveFeedback).
there is no DragDropEffects or DragDropKeyStates in DragEventArgs.
there is no visual for the dragged object or DragDropEffects.
only file drag and drop is supported:
all drop target events fire only when files are being dragged and dropped.
IDataObject, DataObject and DragEventArgs.Data support only one format: “FileDrop”, and the data is of type FileInfo[].
most of IDataObject methods throw NotImplementedException.
for drag and drop to work on Windows, Silverlight plugin must be windowed. In another word, if <param name="windowless" value="true"/> is specified, drop events won’t fire.
since Silverlight plugin on Mac is always windowless, you need to hook up JavaScript drop events to trigger Silverlight drop events. In another word, if you want your Silverlight application to support file drop on Mac as well as Windows, you will need to add following script and Silverlight plugin attributes to the hosting html or aspx page:
<!-- add following script before end of HEAD tag --> <script type="text/javascript"> function handleDragEnter(oEvent) { // Prevent default operations oEvent.preventDefault();
var flag = silverlightControl.dragEnter(oEvent);
// If we handled it successfully then stop propagation of the event if (flag) oEvent.stopPropagation(); }
function handleDragLeave(oEvent) { // Prevent default operations oEvent.preventDefault();
var flag = silverlightControl.dragLeave(oEvent);
// If we handled it successfully then stop propagation of the event if (flag) oEvent.stopPropagation(); }
function handleDragOver(oEvent) { // Prevent default operations oEvent.preventDefault();
var flag = silverlightControl.dragOver(oEvent);
// If we handled it successfully then stop propagation of the event if (flag) oEvent.stopPropagation(); }
// If we handled it successfully then stop propagation of the event if (flag) oEvent.stopPropagation(); } </script> <!-- use JavaScript drop target events to trigger Silverlight's drop target events --> <object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%" id="silverlightControl" ondragenter="handleDragEnter(event)" ondragover="handleDragOver(event)" ondragleave="handleDragLeave(event)" ondrop="handleDropEvent(event)" >
DragEventArgs.Data is only accessible in Drop event. Accessing DragEventArgs.Data in DragEnter, DragOver and DragLeave may cause SecurityException. And accessing Directory, DirectoryName or FullName property of the FileInfo object from DragEventArgs.Data may cause ArgumentNullException.
Demo App
Below is a demo app:
the top left nested grids use drop target event handler to display DragEventArgs info.
the top right nested grids contain an ImageDropTarget user control, which overrides OnDrop method to render the dropped file if it is an image.
the bottom listbox shows the sequence of drop target events, their bubbling up, and DragEventArgs info.
While we are excited to add drag and drop to Silverlight, we know there are a lot to finish/improve, and what we released is just a Beta. As always, your feedback is highly appreciated, and will be used as an important data point to help us prioritize the work. Thanks!
Install, configuration and runtime UI are in Arabic and RTL layout on Arabic culture
Support mixed BiDi/ComplexScript text
Support RTL layout with FlowDirection attribute and implemented by all controls
Below screenshots demonstrate some of the support:
Install UI:
Configuration UI:
Controls with FlowDirection set to RightToLeft:
For those curious, you may notice that:
there is a new ar directory under %programfiles%\Microsoft Silverlight\4.0.41108.0, besides the 10 directories that have been there since SL3: de, en-us, es, fr, it, ja, ko, zh-Hans, zh-Hint. The ar directory contains Arabic resources for Silverlight runtime assemblies.
the MUI resource dlls contain Arabic resources:
We will continue adding more support to more cultures in Silverlight. The Arabic support debuted in Silverlight 4 Beta is particularly important, since it is the first RTL language Silverlight supports. If you notice any bug or have suggestions, please let me know.
Silverlight 4 adds Clipboard support. Check out the amazing demos by Scott Guthrie and Brian Goldfarb today at PDC that showcase scenarios enabled by Silveilght4 Clipboard support.
Silverlight’s Clipboard API is a subset of WPF’s Clipboard API:
It allows copy/paste Unicode strings to/from system clipboard. GetText and SetText require either of following to succeed:
the calling Silverlight application is an elevated trust application, or
it is user initiated and user grants clipboard access
For the second case, when GetText or SetText is first called in an user initiated event handling, Silverlight pops up a dialog like the one below (UI may change at RTW):
If user clicks yes, Silverlight will allow this and later GetText/SetText calls to succeed for this application during this session; if user clicks no, the default, Silverlight will throw a SecurityException. In another word, the setting is per application, per session, for both get and set access to system clipboard, and it is not persisted.
Clipboard API in JavaScript and WPF
We need to consider many factors while designing Clipboard API for Silverlight. Among them, the Clipboard APIs of JavaScript and WPF are particularly interesting, because we need to study the security lessons in JavaScript and try to be compatible with WPF.
There is no cross browser, cross platform JavaScript API for clipboard access. IE provides clipboardData object that allows get/set/clear strings in system clipboard:
where sDataFormat is a string constant of "Text" or "URL", sData is a string, and bResult is a Boolean.
The first time the clipboadData object is accessed, IE will prompt user to allow the script to access clipboard, and the setting is valid for the session only.
WPF’s Clipboard API supports more and extensible data format via IDataObject, and has helper functions for common formats like text, image, audio, and filedrop.
Silverlight’s clipboard API is ultimately implemented on top of the clipboard APIs of the underlying operating system. Windows’ clipboard APIs are documented at MSDN, below excerpt gives an overview on how to set/get clipboard data:
Cut and Copy Operations
To place information on the clipboard, a window first clears any previous clipboard content by using the EmptyClipboard function. This function sends the WM_DESTROYCLIPBOARD message to the previous clipboard owner, frees resources associated with data on the clipboard, and assigns clipboard ownership to the window that has the clipboard open. To find out which window owns the clipboard, call the GetClipboardOwner function.
After emptying the clipboard, the window places data on the clipboard in as many clipboard formats as possible, ordered from the most descriptive clipboard format to the least descriptive. For each format, the window calls the SetClipboardData function, specifying the format identifier and a global memory handle. The memory handle can be NULL, indicating that the window renders the data on request. For more information, see Delayed Rendering.
Paste Operations
To retrieve paste information from the clipboard, a window first determines the clipboard format to retrieve. Typically, a window enumerates the available clipboard formats by using the EnumClipboardFormats function and uses the first format it recognizes. This method selects the best available format according to the priority set when the data was placed on the clipboard.
Alternatively, a window can use the GetPriorityClipboardFormat function. This function identifies the best available clipboard format according to a specified priority. A window that recognizes only one clipboard format can simply determine whether that format is available by using the IsClipboardFormatAvailable function.
After determining the clipboard format to use, a window calls the GetClipboardData function. This function returns the handle to a global memory object containing data in the specified format. A window can briefly lock the memory object in order to examine or copy the data. However, a window should not free the object or leave it locked for a long period of time.
For now, Silverlight Clipboard API only supports CF_UNICODETEXT format for copy/paste Unicode text to/from clipboard.
The copying application is responsible for placing copied or cut data onto the pasteboard:
The user selects some data and invokes the Copy (or Cut) menu item.
If the application doesn’t already have a reference to the Clipboard pasteboard, it creates one (PasteboardCreate).
The application then takes ownership of the pasteboard and clears the current contents (PasteboardClear).
The application assigns item IDs to the selected data.
If any data is to be promised, the application must register a promise keeper callback function to supply the promised data (PasteboardSetPromiseKeeper).
The application adds one or more flavors of each item to the pasteboard, including either the actual flavor data or a promise with each flavor (PasteboardPutItemFlavor).
The receiving application has a slightly different set of tasks to handle the Paste action:
When the application becomes active, it checks to see if the pasteboard has been modified (PasteboardSynchronize). If so, it obtains a listing of the flavors on the pasteboard. If there are any flavors the application supports, it can enable its Paste menu item.
If the pasted data is to be stored as a file, the receiving application needs to set a paste location before requesting any flavor data. In any other case, the receiving application doesn’t need to worry about whether the paste data was promised or not.
If the copying application’s promise keeper is called, the callback must do the following:
If the data is to be stored as a file, determine the paste location specified by the receiving application.
Generate or otherwise prepare the promised data for transfer.
If the promised data is not be stored as a file, add the flavor and data to the pasteboard. Otherwise, transfer the promised data to the specified file location.
Some time later, when the application quits, or when it no longer needs the pasteboard, the application can release the pasteboard reference.
We are excited to add clipboard support to Silverlight, and see all the important scenarios enabled by this simple API. I am interested in hearing your feedbacks, especially:
any security concerns over Silverlight clipboard API design and implementation
how important it is to add support for other data type/format, and in what priority order
how important it is to make the API extensible, like supporting IDataObject, allowing custom format/flavor and delayed rendering/promised data
Visual Studio 2010 Beta 2 is available now. For Silverlight developers, the most exciting news about VS2010 is that Silverlight designer will be in feature parity with WPF designer, and VS2010 will support multi-targeting for Silverlight development. Silverlight Toolkit team has been working closely with Cider team in providing the design time experience for Silverlight SDK and Toolkit controls. The design time for Silverlight 3 SDK controls has been released with SL3 SDK in August 2009, and is also chain installed by VS2010 Beta2. The design time for Toolkit controls, together with sources for both SDK and Toolkit controls, and their design time, samples, unit tests etc, are in Silverlight ToolkitOctober 2009 Release. We purposely made October 2009 release to be in sync with Visual Studio 2010 Beta 2 on Monday, 10/19/2009. This post demonstrates the new design time experiences for Silverlight controls in VS2010.
Install
VS2010 installs side by side with VS2008. Multiple releases of Toolkit install side by side too. So it is perfectly safe to install VS2010 and Toolkit October 2009 release on your main machine. The only caveat is that if you have a pre August 2009 version of Silverlight 3 SDK installed, you will need to uninstall it first, before installing VS2010. You can install VS2010 Beta2 from http://msdn.microsoft.com/en-us/vstudio/dd582936.aspx, and Silverlight Toolkit from http://silverlight.codeplex.com.
Walkthrough
The October 2009 release is for Silverlight 3 only. It provides design time support for both VS2008 and VS2010, as well as Blend 3. Below walkthrough will be VS2010 only. Design time experience for VS2008 and Blend 3 are similar to July 2009 release. Please see my previous posts for design time experience with VS2008 and Blend3.
Create a new Silverlight Application project in VS2010, notice that:
the toolbox is populated with both SDK and Toolkit controls, with nice icons. If you have Blend3 installed before Toolkit, you may see a lot of Blend controls on the toolbox that are not supposed to. You can safely remove them by right click a control in the toolbox and select delete.
it is a real designer: both the design view and the properties window work!
double click TabControl in the toolbox will add a tabControl1. Notice that:
A reference to System.Windows.Controls.dll is added, together with a xmlns definition: xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
tabControl1 is initialized with a tabItem1, which itself is initialized with a header and <Grid/> content. (via DefaultInitializer)
tabItem2’s default property Header is highlighted. You can type into the text box next to it and change the object typed Header property directly. (via TypeConverterAttribute)
all properties have nice infotip
double click DatePicker on toolbox:
a datePicker1 is added to tabItem2’s <Grid> (via ParentAdapter)
datePicker1 is fully expanded, even though its IsDropDownOpen property is false (via DesignModeValueProvider)
Now click tabItem1, notice that tabItem2’s content is hidden and tabItem1’s is shown:
click Chart on toolbox:
a chart1 is added to the right place, initialized with sample data, and nicely rendered
default property Series is selected in the properties window
click the … button next to Series property to pop up the Collection Editor:
the Select item combobox is populated with the correct types (via NewItemTypesAttribute). The pink background for the icons are fixed now.
the Properties window for the series highlights the default property DependentValuePath, have all properties categorized (like the Data Visualization category), and you can modify the object typed Title property directly in the text box.
Create a simple data class with some simple properties, and add it as a data source, via Data | Show Data Sources menu item:
Just for fun, open the project in Blend 3, you will see very similar design time behaviors:
Conclusion
Above walkthrough is only a peek into all the design time features we have implemented for VS2010. I am very excited that VS2010 now provides a real designer for Silverlight, and I will continue enriching the design time experience for Silverlight in VS and Blend. Your feedback is welcome.
I will write a series of posts explaining how those design time experience are implemented.
I have been very busy and haven’t post for a while, so this is a quick late post on Toolkit July 2009 Release. This release is the last Toolkit release for Silverlight 2: when a new version of Silverlight RTMs, we drop support for the previous version, so each Toolkit release needs to support at most two versions of Silverlight. As for design time feature updates, there have been a lot of improvements over March 2009 Release. I will use a simple walkthrough to highlight a few noticeable new features:
Add an Expander control, and set it as the new active container:
Add a DatePicker to the Expander, notice that both the DatePicker and its Calendar drop down are shown, even though both Expander’s IsExpanded and DatePicker’s IsDropDownOpen are false.
Select LayoutRoot so Expander and the nest DatePicker are no longer selected, notice that both are now collapsed.
Open the project in Visual Studio,notice that the Toolbox is populated with lots of controls from Silverlight SDK and Toolkit, with nice icons.
So far, design time features for Silverlight are mostly exposed through Blend. This will change with next beta of Visual Studio 2010, which will come out soon, according to this Visual Studio Magazine article. Stay tuned!
This is part of the series on design time feature implementation in Silverlight Toolkit. This post uses the Chart default initializer to illustrate how to implement default initializer for Silverlight controls, and explain the underlying editing model architecture.
Experience
If you install Silverlight 3 Toolkit in March 2009 Release, you can drag the Chart control from Blend Asset Library and drop it onto designer surface, and you have a chart nicely initialized and rendered:
associate the default initializer class with the control class via a FeatureAttribute
Below screenshot shows the implementation of DefaultInitializer abstract base class, and other classes in Microsoft.Windows.Design.Model namespace that will be discussed shortly:
Initialization is done in InitializeDefaults override, and result is serialized into xaml. So the first step in implementing a default initializer is to define the desired xaml to be produced.
Editing Model
Once the result xaml is defined, I wish there is a higher level abstraction/method that would just take the xaml. But unfortunately we have to use a much lower level (thus more flexible and powerful) imperative API called editing model that consists of classes like ModelItem, ModelProperty, ModelEvent, ModelFactory and ModelService. The MSDN page Editing Model Architecture gives an basic overview:
Your design-time implementation interacts with run-time controls though a programming interface called the editing model. The objects being designed are called editable objects.
Your controls are defined in Extensible Application Markup Language (XAML). You update the XAML for your controls programmatically by using the editing model.
Model, Wrapper, and View
The editing model consists of three functional subunits: a model, a public wrapper that abstracts the model, and a view that represents the user interface (UI) of the model. The model and the view are separate, but the wrapper and model are closely related. The following illustration shows the relationship among the three subunits.
The design environment uses the ModelItem type to communicate with the underlying model. All changes are made to the ModelItem wrappers, which affect the underlying model. This allows the model to be simple. The ModelItem wrappers handle complex designer features, such as transaction support, undo tracking, and change notifications.
Below class diagram may help explain interactions among core classes of the editing model:
ModelItem: assume variable item is the ModelItem for the Button control above,
Name is persisted as x:Name attribute in xaml: item.Name = “Button” is persisted in xaml as x:Name = “Button”.
ItemType is the Type object of the underlying control, and decides the tag used in xaml: item.PropertyType == tyepof(Button), and the xaml tag is <Button />.
Properties is the collection of properties, wrapped in ModelProperty type, of the underlying control. For example: item[“ClickMode”] = ClickMode.Release will be persisted in xaml as ClickMode="Release".
Content represents the Content property defined in ContentControl (and inherited by its subclasses): item.Content is the ModelItem representing the Rectangle object.
Source: when a ModelItem represents an element that’s a property of another element, Source is the ModelProperty wrapper of that property. For example, item.Content.Value.Source == item.Content // the Rectangle.
Events represents the collection of events of the underlying control, wrapped in ModelEvent type. From my debugging experience, it is always null, so it seems Events property is not yet supported by Blend3 for Silverlight3 yet.
Parent is the the logic parent of the underlying control, wrapped in ModelItem type. ex: item.Parent is the ModelItem for Grid.
Root is the ModelItem wrapper for root visual, ex: item.Root represents the UserControl.
ModelProperty: assume variable prop is the ModelProperty for Button.Content, i.e. prop = item.Content,
Name is the name of the property of the underlying control. It is persisted in xaml as attribute name. ex: prop.Name == “Content”.
PropertyType is the Type object of the property of the underlying control this ModelProperty object represents. ex: prop.PropertyType = typeof(object).
AttachedOwnerType is the Type object of the control that first defines the property this ModelProperty object represents. ex: prop.AttachedOwnerType == typeof(ContentControl) // note: not Button.
Value is the value of the property of the underlying control, wrapped in ModelItem type. ex: prop.Value is the ModelItem representing the Rectangle object.
Parent is the control, wrapped in ModelItem type, of which the property belongs to. ex: prop.Parent == item.
ModelEvent: as mentioned above, item.Events is always null, so it doesn’t seem that ModelEvent is supported in Blend3 for Silverlight3 yet. But assume it works, and variable evt is the ModelEvent for Button.Click, i.e., evt = item.Events[“Click”],
Name is the name of the event. ex: evt.Name == “Click”.
EventType is the type of the event delegate, ex: evt.EventType == typeof(RoutedEventHandler).
Handlers is the string collection of event handlers, ex: evt.Handlers = new string[] { “Button_Click” } will be persisted as Click = “Button_Click”. Note: this is pure speculation, since ModelEvent isn’t yet supported, and I don’t know whether/when/how it will be supported for Silverlight.
Parent is the control, wrapped in ModelItem type, of which this event belongs to. ex: evt.Parent == item.
Implementation
The Chart default initializer class ChartDefaultInitializer is implemented in ChartDefaultInitializer.cs, and registered in ChartMetadata.cs. Both files are in Controls.DataVisualization.Toolkit.Design.csproj of Silverlight.Controls.Design.sln. Please read prior post Design Time Feature Implementation in Silverlight Toolkit for more information.
Result XAML
As the first step, define the result xaml to be produced by ChartDefaultInitializer:
Even though DefaultInitializer is defined in version 3.5 of Microsoft.Windows.Design.Interaction.dll (under %devenvdir%\PublicAssemblies, i.e. c:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\PublicAssemblies on 32bit Windows), it is not supported by Blend2 or Visual Studio 2008 for Silverlight. It is supported by Blend3 and Visual Studio 2010, but they both switch to newer version of Microsoft.Windows.Design*.dll (3.7 for Blend 3 Preview, 4.0 for Blend 3 RTM and Visual Studio 2010), so we need to link against the newer version of MWDs. Please see prior post How to Write Silverlight Design Time for All Designers: Visual Studio 2008, Blend 2; Blend 3, and Visual Studio 2010 for more information.
Please also notice that reference to Silverlight’s System.Windows.dll is aliased, and the PointCollection is specifically called out to be the Silverlight one, not WPF’s. Since WPF and Silverlight share a lot of classes in same namespaces, it is important that Silverlight types, not WPF’s, are used in creating ModelItem and ModelProperty in default initializer for Silverlight controls.
Collections
Please note in below screenshot that while all other property value can be set via ModelProperty.SetValue:
Chart.Series is of collection type (Collection<Series>), so its value has to be set by first creating a ModelItem via ModelFactory.CreateItem for the value, and then add the created ModelItem via ModelProperty.Collection.Add. Otherwise, even though the correct xaml may be generated, Blend won’t refresh to render the Chart control correctly, you have to reload the page to have it rendered correctly.
ChartDefaultInitializer.cs
// (c) Copyright Microsoft Corporation. // This source is subject to the Microsoft Public License (Ms-PL). // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details. // All other rights reserved.
extern alias Silverlight; using System.Windows.Controls.DataVisualization.Charting; using System.Windows.Controls.Design.Common; using Microsoft.Windows.Design.Metadata; using Microsoft.Windows.Design.Model; using SSW = Silverlight::System.Windows; using SSWD = Silverlight::System.Windows.Data; using SSWM = Silverlight::System.Windows.Media;