Showing posts with label Design Time. Show all posts
Showing posts with label Design Time. Show all posts

Nov 30, 2009

Silverlight Design Time Assemblies

Introduction

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:

  1. Metadata for property window, like category, infotip, property editor, binding etc.
  2. Metadata for design surface, like initializer, adorner, context menu, adapters etc.
  3. Toolbox integration, like icons, control registration
  4. 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.

Please see Extensibility Series – WPF & Silverlight Design-Time Code Sharing – Part I and How to Write Silverlight Design Time for All Designers: Visual Studio 2008, Blend 2; Blend 3, and Visual Studio 2010 for more information.

Support Both WPF and Silverlight

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!

 

Oct 21, 2009

Silverlight Design Time: Toolkit October 2009 Release Update

Overview

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 Toolkit October 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:
    Create New Silverlight Application Project
    • 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:
    Add Tab Control from Toolbox
    • 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)
    • Property Items is selected in the Properties window (via DefaultPropertyAttribute)
    • Properties are categorized (via CategoryAttribute), and have tooltip (via DescriptionAttribute)
  • Double click tabControl1 will add an event handler for SelectionChanged event (via DefaultEventAttribute)
    Default Event
  • right click tabControl1, select Add Tab (via PrimarySelectionContextMenuProvider):
    VS10SL3TabAddTabCM
  • A new tabItem2 is added. Notice that:
    VS10SL3TabAddTabResult
    • tabItem2 is initialized with a <Grid/> content
    • 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:
    VS10SL3DatePickerAdd
  • Now click tabItem1, notice that tabItem2’s content is hidden and tabItem1’s is shown:
    VS10SL3TabItemSelect
  • click Chart on toolbox:
    VS10SL3TabAddChartpng
    • 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:
    VS10SL3ChartSeries
    • 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: 
    VS10SL3Binding1
  • Drag MyData over tabItem1’s header and drop it :
    Data Binding
  • Just for fun, open the project in Blend 3, you will see very similar design time behaviors:
    VS10SL3Blend3

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.