Showing posts with label Silverlight Toolkit. Show all posts
Showing posts with label Silverlight Toolkit. Show all posts

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.

Sep 29, 2009

Silverlight Design Time: Toolkit July 2009 Release Update

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:

  • Install Silverlight 3, Blend 3 and Toolkit from http://silverlight.net/getstarted/
  • Open Blend 3, create a new Silverlight 3 Application project
  • Open Asset Library, notice few improvements:
    • the new Asset Library. See Unni’s blog The Blend 3 Asset Library for more info. 
    • the nicer icons and more informative infotip

Blend 3 Asset Library

  • Add an Expander control, and set it as the new active container:
Pin 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.

image

  • Select LayoutRoot so Expander and the nest DatePicker are no longer selected, notice that both are now collapsed.

image

Visual Studio ToolboxOpen 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!

Apr 30, 2009

Register Silverlight Controls with Visual Studio and Blend

 Introduction

This is part of the series on design time implementation changes in Silverlight Toolkit March 2009 Release. This post illustrates the integration of Silverlight Toolkit with Visual Studio and Blend 3 after running Silverlight 3 Toolkit March 2009 Installer, and explains how it is done, so you can register your own Silverlight controls with Visual Studio and Blend too.

Blend Integration

After installing Silverlight 3 Beta1 Tools, Blend 3 Preview, and Silverlight 3 Toolkit March 2009 (please see Silverlight Toolkit Design Time Features: March 2009 Release Update, Silverlight 3 Development with Visual Studio 2008 and Blend 3 section for more information), create a Silverlight 3 Application from Blend 3, we can see that Silverlight Toolkit controls show up automatically in Asset Library:

Toolkit Controls in Asset Library, Controls Tab

Toolkit Controls in Asset Library, Custom Controls Tab 

User can drag and drop Toolkit controls from Asset Library to design or xaml view, and Blend will automatically add assembly reference, xmlns prefix and xaml code, very convenient:

Drag and Drop Chart control from Asset Library

Visual Studio Integration

Open the project in Visual Studio, we can see that Toolkit controls show up automatically in Visual Studio Toolbox, and user can drag and drop controls from Toolbox to design or xaml view as well:

Toolkit Controls in Visual Studio Toolbox 

Besides Toolbox, Toolkit assemblies also show up in Add Reference Dialog:

Add Reference Dialog

and Choose Toolbox Items Dialog:

image

 Implementation

The integration with Visual Studio and Blend is done via registry. If you open “Silverlight 3 Toolkit March 2009.msi” in Orca, you can see the registration magic:

Silverlight 3 Toolkit March 2009.msi in Orca

Register with Visual Studio

AssemblyFoldersEx

Registering with Visual Studio is mostly done via [HKLM|HKCU]\Software\Microsoft\Microsoft SDKs\Silverlight\v3.0\AssemblyFoldersEx:

Visual Studio Registration

The References in Visual Studio page has very good explanation on AssemblyFoldersEx and reference resolution. It is a bit outdate, and is about .net instead of Silverlight, but it is mostly right for Silverlight too. I duplicated the registration schema section below, and modified it to fit Silverlight. Text in small italic fonts are purely hypothetical, meaning: it doesn’t work for Silverlight today; I have it here simply because it is in originally text, works for .NET, and seems making sense for Silverlight to duplicate or to be consistent with .Net.

Registration Schema

Assembly directories can be added to the registry so that the build process can resolve references to assemblies in those directories. Here’s an example of the registry schema.

[HKLM | HKCU]\SOFTWARE\MICROSOFT\Silverlight\

  v3.0

    AssemblyFoldersEx

      Silverlight Toolkit

        @Default = C:\Program Files\Microsoft SDKs\Silverlight\v3.0\Toolkit\March 2009\Libraries\

        @Description = Silverlight 3 Toolkit March 2009

        20090401

          @Default = C:\Program Files\Microsoft SDKs\Silverlight\v3.0\Toolkit\March 2009\20090401

          @Description = April Fool’s Updates

In the above example, there are several interesting fields.

(1) AssemblyFolderBase – The registry path "\SOFTWARE\MICROSOFT\Silverlight" indicates the target framework platform. Typical values for this property are:

\SOFTWARE\MICROSOFT\Silverlight(default) – for Silverlight

\SOFTWARE\MICROSOFT\.NetCompactFramework– for .NET Compact Framework

(2) FrameworkVersion – The version of the frameworks that this component is meant to work against.

(3) AssemblyFoldersSuffix – Describes the sub-target, examples include:

AssemblyFoldersEx (default) – for Silverlight

PocketPC\AssemblyFoldersEx – for the .NET Compact Framework for Pocket PC

SmartPhone\AssemblyFoldersEx – for the .NET Compact Framework for SmartPhone

WindowsCE\AssemblyFoldersEx – for the .NET Compact Framework for WindowsCE

(4) ControlName – The name of the control. In the example above, “Silverlight 3 Toolkit March 2009”. The control vendor chooses this name.

(5) ServicingCode – For service packs that update the same component. In the above example, “20090401”. The control vendor chooses this name.

Toolbox Controls Installer

Jim Nakashima blogged about Toolbox Controls Installer for WPF controls in his post Have you seen the Toolbox Controls Installer? in 2007. Toolbox Controls Installer package is now part of Visual Studio 2008, and kind of works, with a bug that will be fixed in Visual Studio 2010. It can be tweaked to work for Silverlight controls too: set string registry value SilverlightControls instead of WPFControls to 1.

I am working with various teams inside Microsoft to improve the Visual Studio registration story for Silverlight controls. All feedbacks and suggestions are welcome!

 Register with Blend

Registering with Blend is via HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Expression\Blend\v3.0\Toolbox\Silverlight\v3.0:

Blend Registration

Unni Ravindranathan’s blog post Blend 3 Extensibility has more information about this mechanism. One caveat: if the registered assemblies depend on other assemblies, those other assemblies need to be in the same directory as registered assemblies, or registered with AssemblyFoldersEx mentioned above. 

Conclusion

Registration with Visual Studio and Blend makes Silverlight Toolkit controls a lot easier to use for developers. We are constantly looking at improving the registration mechanism in hope to make it simple and consistent across designers (Visual Studio and Blend) and technologies (WPF and Silverlight). All feedbacks are welcome!

Apr 3, 2009

Property Value Editors for Silverlight Controls

Introduction

This is part of the series on design time implementation changes in Silverlight Toolkit March 2009 Release. This post discusses how to enhance property editing experience for Silverlight controls using property value editor and type converter. I will start with describing the overall property editing architecture in WPF/Silverlight designer extensibility framework, then use examples in  Silverlight Toolkit March 2009 Release to demonstrate how it is done, and unique issues/tricks in Silverlight design time development.

Property Editing Architecture

Visually editing object properties is an important part of designers. Designers usually don’t know how to render properties of custom type (struct, class or interface), much less to provide an nice editing user interface. Control developers usually need to provide TypeConverter, PropertyValueEditor, or both, to provide rendering/editing UI and XAML serialization for properties of custom types.

The designer extensibility framework defines three types of property value editor: inline editor, extended editor, and dialog editor, each implemented by a class:

PropertyValueEditor class diagram

Editing UI of those editors are defined by DataTemplate. The property being edited is exposed to editor as DataContext of PropertyValue type. Editor UI usually bind to the underlying property being edited via one of the three properties of PropertyValue: Value, StringValue, or Collection.

PropertyValueEditor

PropertyValueEditor holds a single inline editor defined by InlineEditorTemplate property. Inline editor appears inside the properties window. Below is an simple example of InlineEditorTemplate that uses a TextBox to display and edit a property:

<DataTemplate x:Key="TextBoxEditor">
   <TextBox Text="{Binding Path=Value}"/>
</DataTemplate>
 

ExtendedPropertyValueEditor

ExtendedPropertyValueEditor has two editors: an inline editor inherited from PropertyValueEditor, and an additional extended editor defined by the ExtendedEditorTemplate property. The extended editor is usually popped up by inline editor via PropertyValueEditorCommands.ShowExtendedPinnedEditor or PropertyValueEditorCommands.ShowExtendedPopupEditor command. Below is a simple example: the inline editor is a button; when clicked, it pops up the extended editor that uses a Slider to display and edit the underlying property.
<DataTemplate x:Key="inlineEditor">
   <Button Content="..." Command="{x:Static PropertyEditing:PropertyValueEditorCommands.ShowDialogEditor}"/>
</DataTemplate>
<DataTemplate x:Key="extendedEditor" xmlns:PropertyEditing="clr-namespace:Microsoft.Windows.Design.PropertyEditing;assembly=Microsoft.Windows.Design.Interaction">
   <Slider x:Name="slider" Value="{Binding Path=Value}" />
</DataTemplate>
 

DialogPropertyValueEditor

DialogPropertyValueEditor has two editors too: the inline editor inherited from PropertyValueEditor, and an additional dialog editor defined by DialogEditorTemplate property. The dialog editor is usually popped up by inline editor via PropertyValueEditorCommands.ShowDialogEditor command. Below is a simple example:

<DataTemplate x:Key="inlineEditor">
   <Button Content="..." Command="{x:Static PropertyEditing:PropertyValueEditorCommands.ShowDialogEditor}"/>
</DataTemplate>
<DataTemplate x:Key="dialogEditor" xmlns:PropertyEditing="clr-namespace:Microsoft.Windows.Design.PropertyEditing;assembly=Microsoft.Windows.Design">
   <Grid>
       <Grid.ColumnDefinitions>
           <ColumnDefinition Width="Auto" />
           <ColumnDefinition Width="*" />
       </Grid.ColumnDefinitions>
       <Grid.RowDefinitions>
           <RowDefinition Height="*"/>
           <RowDefinition Height="*"/>
       </Grid.RowDefinitions>
       <TextBlock Text="User Name:" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="0,0,4,4"/>
       <TextBox Text="{Binding Path=Value}" VerticalAlignment="Center" HorizontalAlignment="Stretch" Margin="0,0,4,4" Grid.Column="1"/>
   </Grid>
</DataTemplate>

Implement Custom Property Editor

To implement a custom property editor for a Silverlight control:

  • implement a custom property editor class
  • Associate the custom property editor with a property of a Silverlight control via a AddCustomAttributes call, something like
    attributeTableBuilder.AddCustomAttributes(
       typeof(MyControl),
       "MyProperty",
       new PropertyValueEditor.CreateEditorAttribute(typeof(MyValueEditor)));
    A correctly implemented property value editor must satisfy the following requirements:
  • The property value editor must be designed so that the inline editor and extended editor parts can be used independently.
  • A property value editor must not store state. Property value editors are stateless, might be cached by a host implementation, and can be re-used across multiple property values.
  • A property value editor must not assume that only one value editor part (view/inline/extended) control is active at a given time. For example, a dialog box could have the view part, inline part, and extended UI part active at the same time.
  • A control implemented as part of a property value editor must not store state. A control implemented as part of a value editor should not assume that it will only be bound to one property value. Controls may be recycled to change different property values. Any information that is cached should be flushed if the data model is updated.
  • A control implemented as part of a property value editor must not make any assumptions about the host or its parent controls. The only communication mechanisms that should be used are the PropertyValue data model, by way of the DataContext, and the standard set of commands.
     

Reference Both WPF and Silverlight Assemblies

A design assembly is a .NET/WPF assembly loaded by Visual Studio or Blend, but it usually needs to reference Silverlight assemblies (at least the Silverlight control assembly it provides design time features for). This can create reference ambiguity for design assembly project: it sometimes needs to reference the same fully qualified type in both WPF and Silverlight, say System.Windows.FrameworkElement in both PresentationFramework.dll of WPF and System.Windows.dll of Silverlight. To avoid confusing Visual Studio, you can use extern alias to distinguish WPF and Silverlight references.

For example, see the screenshot below for Controls.DataVisualization.Toolkit.Design project in Silverlight 3 Toolkit in March 2009 Release:

image

  • the project references both PresentationFramework and System.Windows, but System.Windows is under Silverlight alias, instead of the default global alias. The System.Windows reference under Silverlight alias is persisted in .csproj file as below:
    <Reference Include="System.Windows, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e, processorArchitecture=MSIL">
     <SpecificVersion>False</SpecificVersion>
     <HintPath>..\Binaries\System.Windows.dll</HintPath>
     <Private>False</Private>
     <Aliases>Silverlight</Aliases>
    </Reference>
  • in source code, we add
    extern alias Silverlight;
    using SSW = Silverlight::System.Windows;

    and reference Silverlight’s FrameworkElement via SSW::FrameworkElement.

TextBoxEditor

There is a inline editor TextBoxEditor in Controls.DataVisualization.Toolkit.Design project for displaying and editing Title property of object type for  [Area|Bar|Bubble|Column|Line|Pie|Scatter]Series and Chart controls, as shown below:

TextBoxEditor

Text filled in Title field in Properties window on the right shows up automatically in XAML and design views in the middle.

The implementation of TextBoxEditor followed the steps outlined before:

TextBoxEditor.cs

TextBoxEditor.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.

using System;
using Microsoft.Windows.Design.PropertyEditing;
using System.Windows;
using System.Windows.Data;

namespace System.Windows.Controls.DataVisualization.Design
{
   /// <summary>
   /// Simple TextBox inline editor.
   /// </summary>
   public partial class TextBoxEditor : PropertyValueEditor
   {
       /// <summary>
       /// Preserve the constructor prototype from PropertyValueEditor.
       /// </summary>
       /// <param name="inlineEditorTemplate">Inline editor template.</param>
       public TextBoxEditor(DataTemplate inlineEditorTemplate)
           : base(inlineEditorTemplate)
       { }

       /// <summary>
       /// Default constructor builds the default TextBox inline editor template.
       /// </summary>
       public TextBoxEditor()
       {
           FrameworkElementFactory textBox = new FrameworkElementFactory(typeof(TextBox));
           Binding binding = new Binding();
           binding.Path = new PropertyPath("Value");
           binding.Mode = BindingMode.TwoWay;
           textBox.SetBinding(TextBox.TextProperty, binding);

           DataTemplate dt = new DataTemplate();
           dt.VisualTree = textBox;

           InlineEditorTemplate = dt;
       }
   }
}

CultureInfoEditor

My colleague RJ wrote inline editor CultureInfoEditor for TimePicker.Culture property, because the default editing experience for CultureInfo in Blend leads to invalid XAML. Below screenshot shows the CultureInfoEditor uses a ComboBox to display all CultureInfo and generates right XAML.

CultureInfoEditor

CultureInfoEditor is a more complex example than TextBoxEditor, really shows how the underlying property is associated with editor via DataContext property.

CultureInfoEditor.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.

using System.Reflection;
using Microsoft.Windows.Design.PropertyEditing;
using System.Globalization;
using System.ComponentModel;

namespace System.Windows.Controls.Input.Design
{
   /// <summary>
   /// Editor for CultureInfo.
   /// </summary>
   /// <remarks>Currently does not support binding from xaml to the editor.</remarks>
   public class CultureInfoEditor : PropertyValueEditor
   {
       /// <summary>
       /// The ComboBox being used to edit the value.
       /// </summary>
       private ComboBox _owner;

       /// <summary>
       /// Preserve the constructor prototype from PropertyValueEditor.
       /// </summary>
       /// <param name="inlineEditorTemplate">Inline editor template.</param>
       public CultureInfoEditor(DataTemplate inlineEditorTemplate)
           : base(inlineEditorTemplate)
       { }

       /// <summary>
       /// Default constructor builds a ComboBox inline editor template.
       /// </summary>
       public CultureInfoEditor()
       {
           // not using databinding here because Silverlight does not support
           // the WPF CultureConverter that is used by Blend.
           FrameworkElementFactory comboBox = new FrameworkElementFactory(typeof(ComboBox));
           comboBox.AddHandler(
               ComboBox.LoadedEvent,
               new RoutedEventHandler(
                   (sender, e) =>
                   {
                       _owner = (ComboBox) sender;
                       _owner.SelectionChanged += EditorSelectionChanged;
                       INotifyPropertyChanged data = _owner.DataContext as INotifyPropertyChanged;
                       if (data != null)
                       {
                           data.PropertyChanged += DatacontextPropertyChanged;
                       }
                       _owner.DataContextChanged += CultureDatacontextChanged;
                   }));

           comboBox.SetValue(ComboBox.IsEditableProperty, false);
           comboBox.SetValue(ComboBox.DisplayMemberPathProperty, "DisplayName");
           comboBox.SetValue(ComboBox.ItemsSourceProperty, CultureInfo.GetCultures(CultureTypes.SpecificCultures));
           DataTemplate dt = new DataTemplate();
           dt.VisualTree = comboBox;

           InlineEditorTemplate = dt;
       }

       /// <summary>
       /// Handles the SelectionChanged event of the owner control.
       /// </summary>
       /// <param name="sender">The source of the event.</param>
       /// <param name="e">The <see cref="System.Windows.Controls.SelectionChangedEventArgs"/> 
       /// instance containing the event data.</param>
       private void EditorSelectionChanged(object sender, SelectionChangedEventArgs e)
       {
           // serialize with name.
               object DataContext = _owner.DataContext;
               DataContext
                   .GetType()
                   .GetProperty("Value", BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty)
                   .SetValue(DataContext, ((CultureInfo)_owner.SelectedItem).Name, new object[] { });
       }

       /// <summary>
       /// Handles the PropertyChanged event of the context object.
       /// </summary>
       /// <param name="sender">The source of the event.</param>
       /// <param name="e">The <see cref="System.ComponentModel.PropertyChangedEventArgs"/> instance containing the event data.</param>
       private void DatacontextPropertyChanged(object sender, PropertyChangedEventArgs e)
       {
           // deserialize from name.
           if (e.PropertyName == "Value")
           {
               object value = sender
                   .GetType()
                   .GetProperty("Value", BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty)
                   .GetValue(sender, new object[] { });

               if (value != null)
               {
                   if (value is string)
                   {
                       CultureInfo setCulture = new CultureInfo(value.ToString());
                       _owner.SelectedItem = setCulture;
                   }
               }
           }
       }

       /// <summary>
       /// Called when the context is changed.
       /// </summary>
       /// <param name="sender">The sender.</param>
       /// <param name="e">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
       private void CultureDatacontextChanged(object sender, DependencyPropertyChangedEventArgs e)
       {
           INotifyPropertyChanged old = e.OldValue as INotifyPropertyChanged;
           if (old != null)
           {
               old.PropertyChanged -= DatacontextPropertyChanged;
           }
           INotifyPropertyChanged newDataContext = e.NewValue as INotifyPropertyChanged;
           if (newDataContext != null)
           {
               newDataContext.PropertyChanged += DatacontextPropertyChanged;
           }
       }
   }
}

ExpandableObjectConverter

As discussed at the beginning, besides custom property value editors, sometimes you can use appropriate type converter to provide good editing experience and XAML serialization. One example is ColumnSeries.DependentRangeAxis: it is of IRangeAxis type, Blend doesn’t know how to edit it, so it shows DependentRangeAxis as read only in Properties Panel. By associating ExpandableObjectConverter to ColumnSeries.DependentRangeAxis:

b.AddCustomAttributes(
   Extensions.GetMemberName<ColumnSeries>(x => x.DependentRangeAxis),
   new TypeConverterAttribute(typeof(ExpandableObjectConverter)));
b.AddCustomAttributes(
   Extensions.GetMemberName<ColumnSeries>(x => x.IndependentAxis),
   new TypeConverterAttribute(typeof(ExpandableObjectConverter)));

Blend displays a New button next to this property in Properties Panel; when clicked, it pops up the Select Object dialog, filtered with the property’s type IRangeAxis:

ExpandableObjectConverter

Conclusion

Blend and Silverlight together allow designers to create amazing UI against real controls directly, so it is very important that control developers take designer experience as part of overall control design and implementation. Having a custom property editor that provides nice editing UI and generates correct XAML is an important part of the designer experience. Hopefully this post helps you understand how to create custom property editors. Thanks!

Jan 24, 2009

Silverlight Controls

Summary

This post describes controls in Silverlight 2, Silverlight 2 SDK, and Silverlight Toolkit December 2008 Release, and their designer support. Based on their shipping vehicles, there are three types of Silverlight controls from Microsoft: runtime controls, SDK controls, and Toolkit controls. Designer support for runtime and SDK controls are spread over Visual Studio, Blend, and Silverlight SDK; while designer support for Toolkit controls are fully implemented by design assemblies in the Toolkit, using designers' extensibility framework.

Runtime Controls

Silverlight runtime comes with a set of basic controls, like Button, Canvas, Ellipse, and TextBox. It also exposes some base classes like Control, UserControl and Panel, to allow users to customize, extend and build their own controls. All run time controls are in System.Windows.dll under %ProgramFiles%\Microsoft Silverlight\2.0.31005.0\:

System.Windows.dll in reflector

Please note the XmlnsDefinition attributes above. Runtime controls live in the default xmlns http://schemas.microsoft.com/winfx/2006/xaml/presentation, so their tags don't need any xmlns prefix, as shown in below xaml:

<UserControl 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="MySLApp1.Page"
    Width="640" Height="480"> 
    <StackPanel x:Name="LayoutRoot" Background="White">
        <Button x:Name="Button" />
    </StackPanel>
</UserControl>

SDK Controls

Silverlight 2 SDK is a separate package from Silverlight runtime. You can install it from http://silverlight.net/GetStarted:

Install Silverlight SDK

It is part of the Silverlight Tools for Visual Studio 2008 SP1 download, which also includes Silverlight 2 developer runtime. Silverlight 2 SDK adds two control dlls: System.Windows.Controls.dll and System.Windows.Controls.Data.dll.

System.Windows.Controls.dll

System.Windows.Controls.dll in reflector

System.Windows.Controls assembly adds four main controls: Calendar, DatePicker, GridSplitter, TabControl, and their supporting classes, to the same two CLR namespaces: System.Windows.Controls & System.Windows.Controls.Primitives, in which most runtime controls also live. All controls in System.Windows.Controls assembly are in the xmlns "clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls", and usually use the "basics" xmlns prefix, as shown in below Xaml:

<UserControl 
    xmlns:basics="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
    xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
    xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
    x:Class="MySLApp1.Page"
    Width="640" Height="480"> 
    <StackPanel x:Name="LayoutRoot" Background="White">
        <basics:Calendar></basics:Calendar>
    </StackPanel>
</UserControl>

System.Windows.Controls.Data.dll

System.Windows.Controls.Data assembly adds the all mighty DataGrid control and its supporting classes to the same two CLR namespaces, System.Windows.Controls & System.Windows.Controls.Primitives, just like the runtime assembly System.Windows and the SDK assembly System.Windows.Controls.

System.Windows.Controls.Data.dll in reflector

System.Windows.Controls.Data controls (just DataGrid for now) are in the xmlns "clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data", and usually use the "data" xmlns prefix, as shown in below Xaml:

<UserControl 
    xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
    xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
    xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
    x:Class="MySLApp1.Page"
    Width="640" Height="480"> 
    <StackPanel x:Name="LayoutRoot" Background="White">
        <data:DataGrid></data:DataGrid>
    </StackPanel>
</UserControl>

Toolkit Controls

Silverlight Toolkit is yet another separate package that you can install from http://silverlight.net/GetStarted:

Silverlight Toolkit

You can also install it directly from Toolkit's home page: http://www.codeplex.com/Silverlight.

Once installed, the Silverlight Toolkit adds four more control assemblies:

Silverlight Toolkit

Each assembly introduces a new xmlns prefix and a set of controls under it:

  • System.Windows.Controls.dll
    • xmlns:controls="clr-namespace:Microsoft.Windows.Controls;assembly=Microsoft.Windows.Controls"
    • Main controls: AutoCompleteBox, DockPanel, Expander, HeaderedContentControl, HeaderedItemsControls, Label, TreeView, Viewbox, WrapPanel
  • System.Windows.Controls.Input.dll
    • xmlns:input="clr-namespace:Microsoft.Windows.Controls;assembly=Microsoft.Windows.Controls.Input"
    • Main controls: NumericUpDown, ButtonSpinner
  • System.Windows.Controls.Theming.dll
    • xmlns:theming="clr-namespace:Microsoft.Windows.Controls.Theming;assembly=Microsoft.Windows.Controls.Theming"
    • Main controls: ImplicitStyleManager, Theme (concrete Theme classes are implemented in assemblies under Themes directory)
  • System.Windows.Controls.DataVisualization.dll
    • xmlns:charting="clr-namespace:Microsoft.Windows.Controls.DataVisualization.Charting;assembly=Microsoft.Windows.Controls.DataVisualization"
    • Main controls: Chart, [Category|DateTime|Linear]Axis, [Bubble|Bar|Column|Line|Scatter|Pie]Series

Below screenshot shows a Silverlight application using the four Toolkit assemblies:

Toolkit Application in Visual Studio

Designer Support

The two Silverlight designers from Microsoft are Visual Studio 2008 SP1 and Expression Blend 2 SP1. Designer support for Visual Studio 2008 SP1 (VS9) is mostly about toolbox icon and IntelliSense, as shown in above screenshot. Designer support for Blend 2 is mostly about metadata registration, like Description, Category, Browsable, ToolboxBrowsable etc attributes, as shown by below screenshot:

Toolkit Application in Blend

Designer Support for Runtime and SDK Controls

Below screenshots demonstrate designer support for Silverlight runtime and SDK controls:

  • Visual Studio has toolbox icons and IntelliSense for runtime and SDK controls:

Visual Studio

  • Blend has rich support (Icons, Categories, Descriptions, inline/extended/dialog Editors etc) for runtime and SDK controls:

Blend

The design time assemblies for runtime and SDK controls are installed by Silverlight SDK:

Silverlight SDK

  • System.Windows.VisualStudio.Design.dll for runtime controls in System.Windows.dll
  • System.Windows.Controls.Design.dll & System.Windows.Controls.xml for SDK controls in System.Windows.Controls.dll
  • System.Windows.Controls.Data.Design.dll & System.Windows.Controls.Data.xml for SDK controls in System.Windows.Controls.Data.dll

If we open those design dlls in reflector, we can see that they don't do much other than providing toolbox icons for Visual Studio:

System.Windows.VisualStudio.Design.dll in reflector

System.Windows.Controls.Design.dll in reflector

System.Windows.Controls.Data.Design.dll in reflector

There is no metadata registration, nor nice icons displayed by Blend. So the rich designer support for runtime and SDK controls in Visual Studio and Blend are actually implemented by the designers themselves, instead of design assemblies for those controls. This creates tight coupling between tools (VS9 and Blend2) and controls (runtime and SDK controls).

Designer Support for Toolkit Controls

On the other hand, designer support for Toolkit controls are fully implemented by design assemblies in Toolkit, built on top of designer extensibility framework:

Silverlight Toolkit Design Dlls

You can get more information about Toolkit design time features and their implementation from following posts:

Conclusion

So we have three vehicles for shipping Silverlight controls:

  • The Toolkit is open-source on Codeplex and ships every few months. This enables us to "add new functionality quickly for designers and developers, and provide the community an efficient way to help shape product development by contributing ideas and bug reports."
  • For those controls that are well baked, widely adopted and reached mature quality band, we may move them to SDK.
  • Over time some of the SDK controls may merge into Silverlight runtime.

Silverlight revolutionizes web development by converging web and desktop development technologies (languages, platforms, tools etc), unifying web and desktop, and bringing the power of desktop to web client. Silverlight Toolkit team is like an agile ISV inside Microsoft, continuously and aggressively enriching and empowering the Silverlight platform, as well as pioneering a new agile, collaborative and open-sourced engineering model. The idea was started by Shawn Burke and Scott Guthrie, as described in Shawn's blog post Control Freak.

Jan 21, 2009

How to Add an Toolbox Icon for Your Silverlight Control

Controls in Silverlight runtime (system.windows.dll) and SDK (system.windows.controls.dll) have nice toolbox icons in Visual Studio. December 2008 release of Silverlight Toolkit added that for Toolkit controls too, as described in my previous post Design Time Features in Silverlight Toolkit:

custom icons

This post explains how it is done in Silverlight 2 SDK, and in December 2008 release of the Silverlight Toolkit.

 

Control Icons in Run Time Assembly

The December 2008 Release of Silverlight Toolkit demonstrated how to embed toolbox icons for controls without using a design time assembly.

Open Silverlight.Controls.sln in Visual Studio (see previous post Design Time Feature Implementation in Silverlight Toolkit for more information on how to download the toolkit source):

Embed icons in run time assembly, visual studio view

Or open Controls.csproj in notepad:

<ItemGroup>
  <EmbeddedResource Include="Microsoft.Windows.ControlsAutoCompleteBox.Icon.png" />
  <EmbeddedResource Include="Microsoft.Windows.ControlsDockPanel.Icon.png" />
  <EmbeddedResource Include="Microsoft.Windows.ControlsExpander.Icon.png" />
  <EmbeddedResource Include="Microsoft.Windows.ControlsLabel.Icon.png" />
  <EmbeddedResource Include="Microsoft.Windows.ControlsTreeView.Icon.png" />
  <EmbeddedResource Include="Microsoft.Windows.ControlsViewbox.Icon.png" />
</ItemGroup>

Or open Microsoft.Windows.Controls.dll in reflector:

 Embed icons in run time assembly, reflector view

All three show that the custom toolbox icons are embedded resources in the run time assembly Microsoft.Windows.Controls.dll, with a particular naming convention. Take above Microsoft.Windows.Controls.Microsoft.Windows.AutoCompleteBox.Icon.png as an example:

  • The first Microsoft.Windows.Controls is the root namespace, specified in controls.csproj file with line: <RootNamespace>System.Windows.Controls</RootNamespace>
  • The next Microsoft.Windows.Controls.AutoCompleteBox is the fully qualified name of AutoCompleteBox class, including namespace but not assembly.
  • The rest of the name, Icon.png, specify the icon resource type, as will be explained more later.

Control Icons in Design Time Assembly

The Silverlight 2 SDK demonstrated the approach of embedding control icons in design time assembly.

Open System.Windows.Controls.Design.dll in reflector (it is installed under %ProgramFiles%Microsoft SDKsSilverlightv2.0LibrariesClient):

embed icon in design time assembly, reflector view

Take above Controls.Design.Icons.Calendar.bmp as an example:

  • Controls.Design is the root namespace, specified in its csproj file with line <RootNamespace>Controls.Design</RootNamespace>
  • Icons is the subfolder where the Calendar.bmp file is in source tree
  • Calendar.bmp is the name of the icon resource file in source tree

Control Icon Resource Naming Convention

So from above two examples, we can see that custom toolbox icons for controls are embedded resources in either run time assembly (so you don't need to ship a design time assembly), or design time assembly (so you have flexibility to change icons, like localize it for a different culture, without touching the run time assembly). The tools (Visual Studio 2008 SP1 for now) try to find the icons based on a special naming convention:

  1. Search for resources whose file name without extension matches the type name of the control, including the namespace with a “.icon[*].{XAML | BMP| PNG | GIF | JPG | JPEG}” .
    1. Note that subdirectories affect the namespace in which embedded resources are found. For example, the Toolkit icons are put under a Microsoft.Windows.Controls subfolder, to avoid putting this long string in all icon file names; while the SDK put all icons under a Icons subfolder.
    2. Supported extensions and file types are: XAML, BMP, GIF, JPG, JPEG and PNG
    3. Recommended image size for Bitmap based file formats is 64x64.
    4. The .icon[*] in the naming convention is optional and allows the Control Dev to specify multiple sizes of the image that is used as the icon. The match follows the following algorithm:
      1. Vector XAML
      2. If there is an exact match on size (both dimensions) use it
      3. Use the closest match based on size and aspect ratio
    5. If a given resource file is not valid XAML or a valid image file, the next match will be used until one is found.
  2. If an image is not found in the same namespace as the control, a loose match based on the type name alone will be searched for against all of the resources, as in the SDK case.
  3. Different hosts use different image sizes for their toolbox icon.
    1. Blend uses 24x24 for their large size and 12x12 for their small size (I don't think this is working in Blend 2 SP1)
    2. Cider (Visual Studio) uses 16x16

The blog post Specifying a Toolbox Icon for a Control in WPF Designer describes the naming convention in more details.

 

Hope this helps. Thanks!