Enabling Business Application Development

Printing

Silverlight adds printing support that allows developers to control whether their Silverlight application can print itself, how the content is formatted when printed, and determine the content that will appear. For example, you could add a print button to your Silverlight application that opens the Print dialog allows the user to choose the printer, and then prints the Silverlight content.

You can print content by first creating an instance of the PrintDocument class, then specifying the content to print, and finally writing code to handle the PrintPage event. You can print the entire Silverlight control by setting PrintPageEventArgs.PageVisual to the layout root of the Silverlight content. Alternatively, you can print a portion of the Silverlight content by setting PrintPageEventArgs.PageVisual to the named UIElement you wish to print. The following code sample prints all content within the UIElement named in the Silverlight application.

C#

PrintDocument pd = new PrintDocument(); pd.PrintPage += (s, args) => { args.PageVisual = LayoutRoot; }; pd.Print();

After the PrintPage event occurs, the content from the PageVisual is sent to the selected printer to be printed. Content that is too large to fit in to the PrintableArea will be clipped. If HasMorePages is true, PrintPage occurs multiple times until HasMorePages is false. If you require customized printing options, you can write code for the StartPrint and EndPrint events to perform special handling.

You can print content that is not in the live visual tree. This allows you to make your printed content look different from your onscreen content. To do this, set PageVisual to a UIElement created in the PrintPage event without adding it to the live visual tree. Another tip to print elements which are not in the live tree is to explicitly run layout on them by calling measure and arrange.

Localization with Bi-Directional and Script-Based Text and Right-to-Left Support

Silverlight introduces support for shaped and script languages that flow right to left, such as Arabic and Hebrew. The ability to change the direction of the flow is available to all Silverlight UI elements by setting the FlowDirection property to LeftToRight or RightToLeft. The default bi-directional (Bi-Di) FlowDirection property is from LeftToRight. Setting FlowDirection to RightToLeft on any element sets the alignment to the right, the reading order to right-to-left, and the layout of the control to flow from the right to the left. Most UIElement controls inherit the FlowDirection from their parent; however Image, MediaElement, MultiScaleImage, and Popup do not and remain LeftToRight unless overridden explicitly. When brushes and effects are applied to elements whose FlowDirection property is set RightToLeft, the result is flipped horizontally.

Extended Language Support

Silverlight 4 now supports several new languages including Thai and Vietnamese as well as multiple Indic scripts both for rendering and input. The following Indic scripts are now supported:

Script

Languages

Bengali

Bengali, Assamese, Manipuri

Oriya

Oriya

Malayalam

Malayalam

Kannada

Kannada

Tamil

Tamil

Telugu

Telugu

Gujarati

Gujarati

Gurmukhi

Punjabi

Devanagari

Hindi, Marathi, Sanskrit, Konkani, Kashmiri, Nepali, Sindhi

RichTextBox Control

Silverlight adds the new RichTextBox control to the standard controls offered by Silverlight. Through the FlowDirection property, the RichTextBox has Bi-Directional (Bi-Di) support on content including Runs. It also allows hyperlinks, XAML content, embedding of images, changing the font size, foreground color, and making text bold, italicized, and underlined as well as many other rich text features.

The RichTextBox supports the “format then type” feature. For example, with this feature you can choose a format, such as bold or font color of green, and when you start typing the formatting selections you made are applied to the text you type. Text position and selection APIs are also supported.

Another feature of the RichTextBox control is paragraph blocks, which allows different formatting of blocks of text. Built-in keyboard commands can be used to allow shortcuts for clipboard and undo operations. The RichTextBox also supports mouse events, XAML to clipboard features, undo, and language localization.

The following image shows the RichTextBox control using the FlowDirection = RightToLeft and displaying Hebrew text.

Figure 2

RichTextBox with FlowDirection of RightToLeft

The following image shows a sample application with a RichTextBox control containing several different types of content, including embedded images, an embedded Silverlight DataGrid, different font sizes, different fonts, foreground colors, bold, and italics.

Figure 3

RichTextBox Control

The RichTextBox has a Xaml property that supports serializing text content. You can get the Xaml from the RochTextBox’s Xaml property and save it to isolated storage or perhaps send it to a web service. You can also set the content of the RichTextBox control by setting the Xaml property. You can clear the content of a RichTextBox by calling the Blocks property’s Clear method.

Text Input

Silverlight now enhances its support for IME (Input Method Editors), which is a part of text input used when there are more glyphs than keyboard keys (as with East Asian languages). Enhancements include getting and setting IME conversion modes as well as getting and setting IME active state. In addition, the TextInputStart, TextInputUpdate, and TextInput events have been added to the UIElement controls. These events are effective at determining the text that users input when using IME.

Silverlight also has additional event handling for text input via the TextInput event. The TextInput event allows you to get an event from key press generated characters. This includes getting characters that require multiple keyboard presses in order to be entered, such as the “è” in the name “Claudè”.

Viewbox Control

Silverlight adds the Viewbox to its list of layout containers. The Viewbox allows precise positioning and flexible resizing support that stretches or scales a single child element to fit the available space. A Viewbox can only contain a single element.

The Viewbox’s StretchDirection property determines how to scale its contents. It prevents the contents of the Viewbox from being scaled to a smaller or larger dimension than the original. Possible values are UpOnly, DownOnly and Viewbox Control Both. The Stretch property determines how the content of the Viewbox will be stretched to fill the Viewbox. Possible values are None, Fill, Uniform, and UniformToFill.

The example below shows a Viewbox control with the default settings of Stretch=Uniform and StretchDirection=Both. The image inside the Viewbox is 200x200 pixels and will be stretched uniformly to fill the entire smaller Viewbox.

XAML

<Grid x:Name="LayoutRoot" Background="Red" Width="100" Height="100" > <Viewbox Margin="5"> <Image Source="sl4 image.png"/> </Viewbox> </Grid>

Figure 4

Viewbox with Default Settings

If you set the StretchDirection to UpOnly, then the image will only stretch up in size. Since the container is smaller than the image, the image will not stretch and only the upper portion of the image will be visible.

Figure 5

Viewbox with StretchDirection = UpOnly

Auto-Sizing Columns and Copy from DataGrid

Silverlight added several new features to the DataGrid control. Through auto-sizing columns, the DataGrid in Silverlight now has the ability to allow columns to share the remaining width of a DataGrid. This feature makes it easy to define specific widths for some columns in a DataGrid while allowing the other columns to share the remaining width of the DataGrid. For example, you might want to have fixed widths for columns for City, State, and the Postal Code. However, you may want the Name column to use 1/3 of the remaining space and the Address column to use 2/3 of it. The following code would accomplish this using * column widths:

XAML

XAML <data:DataGrid AutoGenerateColumns="False" x:Name="dataGrid2" HeadersVisibility="All"> <data:DataGrid.Columns> <data:DataGridTextColumn Header="Name" Binding="{Binding Name}" Width="*"/> <data:DataGridTextColumn Header="Address" Binding="{Binding Address}" Width="2*"/> <data:DataGridTextColumn Header="City" Binding="{Binding City}" Width="100"/> <data:DataGridTextColumn Header="State" Binding="{Binding State}" Width="50" /> <data:DataGridTextColumn Header="Postal Code" Binding="{Binding PostalCode}" Width="80"/> </data:DataGrid.Columns> </data:DataGrid>

Figure 6

DataGrid with Auto Sizing Columns

The DataGrid now supports MouseWheel scrolling and the FlowDirection property. In addition, DataGrid supports row level copy. This means you can copy a row of a DataGrid to the clipboard and then paste it to another program.

Silverlight 3 introduced page navigation that resolves URIs into pages. Every page had to have an associated XAML and navigating to that page required URIs with paths to those XAML files based upon your project’s file structure. Silverlight 4 adds a public ContentLoader property to the Frame control and the INavigationContentLoader interface. Together, these changes allow the developer to generate and initialize instances of pages from URIs using their own scheme, and enable scenarios such as authentication redirects, error pages, and MVC-style navigation.

Silverlight adds commanding support commonly used in the Model-View-ViewModel (MVVM) pattern, which provides separation between the View (the Silverlight user control) and the ViewModel (the logic and bindings for the View). Silverlight adds support for commanding on controls that inherit from ButtonBase and Hyperlink. The Command and CommandParameter are exposed to allow binding from a View to a ViewModel without the need for code in the codebehind. You can implement a command by first creating your own DelegateCommand and binding to it from the XAML.

For example, a ViewModel may contain a LoadProducts command, which implements the ICommand interface. The LoadProductsCommand accepts a parameter that filters the products that start with a specific letter(s). The following XAML shows how a Button’s Command property could be bound to the LoadProductsCommand and how its CommandParameter property could be bound to a TextBox’s Text property.

XAML

<UserControl.Resources> <local:ProductViewModel x:Key="vm"/> </UserControl.Resources> <Grid DataContext="{StaticResource vm}" Name="LayoutRoot"> <TextBox x:Name="MyFilterTextBox"/> <Button Content="Load" Width="120" Command="{Binding LoadProductsCommand}" CommandParameter="{Binding Path=Text, ElementName=MyFilterTextBox}"/>

This XAML binds the Button to the LoadProductsCommand in the ViewModel. You can enable or disable the Button depending on the Boolean return value from the command’s CanExecute method.

SelectedValue and SelectedValuePath on the Selector

These properties enable the use of ComboBox as a look up table. When combining DisplayMemberPath with these you can display one thing but bind to another. All controls that inherit from the Selector class now have SelectedValue and SelectedValuePath properties. You can now set the SelectedValuePath property to the string name of the property of the SelectedItem. When this is set, the SelectedValue property will return the SelectedItem’s property with the matching name of the SelectedValuePath.

For example, you have a control that derives from Selector (such as the ComboBox control) and it is bound to a collection of Product classes. The Product class has ProductName and ProductId properties. If the SelectedValuePath is set to ProductName , when an item in the Selector control is selected, the SelectedValue property will return the value for the ProductName of the SelectedItem. The following XAML demonstrates this example.

XAML

<UserControl.Resources>
FakePre-d897ec989901491b9ff4228bafea27ec-6b36702e12664f80a92a49929810e842FakePre-e1a29abce3da442cb2608ddc61570755-955742ea478b4efc8b90a9a40bf02b97FakePre-78022ede40ed4e9c9ccacce1b986efe3-0cbf22d4c8cf4e2b94623ed249d3b6aeFakePre-f8e2fb8c164b465c81721c27e94c95f3-266684128b3242fe80f8a355b024a10fFakePre-d58127ac9ea44d7bb1ac04a4915d5c42-e9adc9750ebc451d8e8f08e3ea015843FakePre-53253b582a2a47a6a7ff5e075ef93ea7-1c9b13e6089b4d0d932c1cced11b32eaFakePre-7c034862ee2f486489e3aafe586f065d-50dbbcd3f3e344799fe91a7b1d96ec6bFakePre-5e7bbad9f0d74c53ae8331099f5e0388-9c02ca229aba4ff2b8d83c1e5e5dfcfdFakePre-cd3b789f6faf4544b11a76217af8c3df-cfb59a89b2834974bdcce96164ff4346FakePre-cf4b339e6a764e4a82f2efd248a8f01b-021270ee38b24a20b2fc991225beceabFakePre-ff673e042abe45e791875f18450a82db-08763e849c2f4a558f5689f516ea2c11SelectedValuePath="ProductName"FakePre-e6bf11cd99eb49b0aeb7c2e35254a7ec-7817a3af4e2142a490e0d21792c04043FakePre-489f2fbc902446368b1f9a0d80b7e1bd-558007fec8e14a109688ca4fcb2861dcFakePre-fdd8c88a60db4d478c54e007b6f9c279-38d810629f2f4cd5951991b328424f81FakePre-89d201f8321f4597a9dcf8c8882cacc1-3b112db3b4a740ce98e52d7270b7f0b4FakePre-dd51a5c6be51424f889bed06e9e3667e-609666ca3a9c476d9005de8b199ca4b8FakePre-0a0a96f16a164a9a97a294c4ace1a5a7-80a2f619f715446ea31d1021f77c1cb2

The result of this XAML is that when you select a product, such as Strawberry, the ProductName of the SelectedItem is displayed in the TextBlock, as shown below.

Figure 7

TextBlock Bound to SelectedValue of a ComboBox

Another valuable scenario is when a class, for example a Customer class, has a public string StateId {get;set;} which takes the value “WA” or “NV” etc. You want to display a picker that displays the full state name but when you pick a value pushes the short name into Customer.StateId. You can create a State object with LongName and ShortName and a collection of all the States called StatesCollection. Then you bind ComboBox.ItemsSource to StatesCollection with DisplayMemberPath=LongName, SelectedValuePath=ShortName and bind SelectedValue to the current Customer StateId property. In the end, you will display “Washington” but SelectedValue is “WA” and so Customer.StateId gets set to “WA”

XAML

<StackPanel x:Name="LayoutRoot"             Background="White" DataContext="{StaticResource customerVM}" Orientation="Vertical" Margin="10">     <ComboBox Height="23" Name="ProductComboBox" VerticalAlignment="Top" Width="120" SelectedValue=”StateId” DisplayMemberPath=”LongName” SelectedValuePath="ShortName"             ItemsSource="{Binding Source="{StaticResource statesCollection}}" ItemTemplate="{StaticResource ProductDataTemplate}" /> </StackPanel>

Support for Referer Header

Silverlight allows the Referer request header for both in-browser and out-of-browser scenarios on all networking requests used by WebClient and HttpWebRequest when they use the Client networking stack. This enables services like Live Mesh to determine where the requests originated. The Referer header is a request header field that is automatically set to the base URI of the client from which the Request-URI was obtained. The Referer request header allows a server to generate lists of back links to resources for logging and caching optimization.

UDP Multicast Client Support

Silverlight enables UDP multicast for one-to-many communication over an IP infrastructure. This efficiently scales to a large receiver population. There are two key shapes for multicast groups:

  • Single Source Multicast (one-to-many)System.Net.Sockets.UdpSingleSourceMulticastClient
  • Any Source Multicast (many-to-many)System.Net.Sockets.UdpAnySourceMulticastClient

To make multicast group accessible to Silverlight, you need to expose a policy responder (just like Sockets and HTTP).

Networking Enhancements

Silverlight 4 adds the following features to the networking stack:

  • UploadProgress support on the client networking stack now exists. This allows you to be notified as content is being uploaded so you can notify the user.
  • Caching support on the client networking stack has been added.
  • Sockets policy file retrieval via HTTP is also new.
  • Accept-Language header has been added.

WCF TCP-based Binding

WCF in Silverlight now offers a TCP-based binding, which enables communicating with WCF services configured with NetTcpBinding. Note that no security is supported in this release.

WCF PollingDuplex Improvements

PollingDuplex now supports a new “multiple messages per poll” mode, where HTTP chunking is used to stream many messages in response to a client poll.

Authentication Support with ClientHttpWebRequest

Silverlight adds the ability to pass user credentials from the application to the server to support NTLM, Basic, and Digest authentication. This allows Silverlight applications to pass user credentials for authentication by services such as ADO.NET Data Services or Live Mesh.

A Silverlight application can now set the Credentials API with a username and password when Web sites require the authorization request header to be sent with a network request to properly authorize users. When a user has already logged in to the machine and the credentials have been saved to the OS, the client may use these default credentials to authenticate when making a client networking request. This makes the most sense in scenarios (such as SharePoint ) that use NTLM authentication.

The code below demonstrates how to pass network credentials using the new APIs. Notice that the UseDefaultCredentials property is set to false. When UseDefaultCredentials is set to true, the Credentials property is ignored and the credentials are retrieved from the local machine’s session. In the code above, the credentials are supplied in code, so the UseDefaultCredentials must be set to false.

C#

var username = "myTwitterId"; var password = "myTwitterPassword"; var twitterUri = @"https://twitter.com/statuses/friends_timeline/{0}.xml?count=50"; var uriString = string.Format(twitterUri, username); WebClient request = new WebClient(); WebRequest.RegisterPrefix("https://", WebRequestCreator.ClientHttp); request.UseDefaultCredentials = false; request.Credentials = new NetworkCredential(username, password); request.DownloadStringCompleted += new DownloadStringCompletedEventHandler(client_DownloadStringCompleted); request.DownloadStringAsync(new Uri(uriString));

Custom authentication is now supported for in browser and out of browser applications through programmatic access to the Authorization header via the Headers collection on WebRequest. Also, you will need the clientaccesspolicy.xml file to opt-in to the Authorization header being sent.

IDataErrorInfo

Silverlight adds the IDataErrorInfo interface enables the reporting of validation errors that a user interface can bind to. When an entity implements this interface and the entity is involved in a binding operation, it invokes the indexer to validate the properties. The bound target properties in the UI will receive the error messages and display the validation states if the ValidatesOnDataErrors property is set to true.

The IDataErrorInfo interface exposes an Error property and a string indexer. The Error property should return an error message explaining the error with the object. The indexer should return the error message for the property with the given name passed to the indexer.

C#

public interface IDataErrorInfo{string Error { get; } string this[string columnName] { get; }}

You can implement validation by executing the IDataErrorInfo interface on an entity model as shown in the code sample below on the Employee. The Employee has custom validation rules that execute when changes occur in the bound UI elements that have ValidatesOnDataErrors set to true.

C#

public class Employee : INotifyPropertyChanged, IDataErrorInfo { private ValidationHandler validationHandler = new ValidationHandler(); private string _FirstName; public string FirstName { get { return _FirstName; } set { _FirstName = value; NotifyPropertyChanged("FirstName"); bool valid = validationHandler.ValidateRule( "FirstName", "First Name must be at least 5 letters!", () => (value.Length >= 5)); } } private float _TaxPercent; public float TaxPercent { get { return _TaxPercent; } set { if (_TaxPercent != value) { if (value >= 1) value /= 100; _TaxPercent = value; NotifyPropertyChanged("TaxPercent"); bool valid = validationHandler.ValidateRule( "TaxPercent", "The tax has to be positive!", () => (value > 0)); } } } protected void NotifyPropertyChanged(string PropertyName) { if (null != PropertyChanged) PropertyChanged(this, new PropertyChangedEventArgs(PropertyName)); } public event PropertyChangedEventHandler PropertyChanged; public string Error { get { return null; } } public string this[string columnName] { get { if (this.validationHandler.BrokenRuleExists(columnName)) { return this.validationHandler[columnName]; } return null; } } } public class ValidationHandler { private Dictionary<string, string> BrokenRules { get; set; } public ValidationHandler() { BrokenRules = new Dictionary<string, string>(); } public string this[string property] { get { return this.BrokenRules[property]; } } public bool BrokenRuleExists(string property) { return BrokenRules.ContainsKey(property); } public bool ValidateRule(string property, string message, Func<bool> ruleCheck) { if (!ruleCheck()) { this.BrokenRules.Add(property, message); return false; } else { RemoveBrokenRule(property); return true; } } public void RemoveBrokenRule(string property) { if (this.BrokenRules.ContainsKey(property)) { this.BrokenRules.Remove(property); } } }

The XAML for these UI elements is shown below.

XAML

<TextBox x:Name="FirstNameTextBox" Text="{Binding Path=FirstName, Mode=TwoWay, ValidatesOnDataErrors=True}" /> <TextBox x:Name="TaxPercentTextBox" Text="{Binding Path=TaxPercent, Mode=TwoWay, ValidatesOnDataErrors=True}" />

When invalid values are entered into these controls, the validation kicks in and displays to the user as shown below.

Figure 8

Data Validation using IDataErrorInfo

INotifyDataErrorInfo

IDataErrorInfo is limited to validating on a per property basis. However, Silverlight 4 also adds the INotifyDataErrorInfo interface that allows validation across properties of an entity. It also allows entity objects to enable notification of data errors in the UI. INotifyDataErrorInfo allows developers to provide custom, asynchronous validation support to access server-side validation logic. It exposes a HasErrors property to indicate if there are any errors and has a GetErrors method to retrieve the errors. The ErrorsChanged event is raised when new errors are added. If the binding property ValidatesOnNotifyDataErrors is set to true and the source object implements the interface, the binding engine in Silverlight will listen for the ErrorsChanged event. INotifyDataErrorInfo also provides entity level validation support to the DataGrid control. WCR RIA Services takes advantage of the INotifyDataErrorInfo interface to perform validation, too.

Grouping on CollectionViewSource

Silverlight adds capabilities to the CollectionViewSource class by enabling grouping over bound data within a Silverlight DataGrid control. A DataGrid’s ItemsSource can be bound to the CollectionViewSource and you can apply a grouping to it. The following code adds 2 new groups to the CollectionViewSource. When it is bound to the DataGrid, the DataGrid will group the items using the GradeLevel and Gender groups.

XAML

<UserControl.Resources> <CollectionViewSource x:Key="cvs"> <CollectionViewSource.GroupDescriptions> <PropertyGroupDescription PropertyName="GradeLevel" /> <PropertyGroupDescription PropertyName="Gender" /> </CollectionViewSource.GroupDescriptions> </CollectionViewSource> </UserControl.Resources> <Grid x:Name="LayoutRoot"> <DataGrid ItemsSource="{Binding Source={StaticResource cvs}}" /> </Grid>

Editable CollectionView IEditableCollectionView

When a CollectionViewSource is used as the ItemsSource of both a Silverlight DataForm and a DataGrid, the DataForm can use its Add button to add items to the collection. Also, the item can be edited, cancelled, or committed. The item also appears in the DataGrid, which the CollectionView keeps in sync with the DataForm. You can cancel the editing an item in the DataGrid by hitting the escape key twice while editing a field. Both the DataGrid and DataForm perform entity-level validations whenever CommitEdit() is called, giving the user immediate feedback.

XAML

<UserControl.Resources> <CollectionViewSource x:Key="cvs"/> </UserControl.Resources> <Grid x:Name="LayoutRoot"> <DataGrid ItemsSource="{Binding Source={StaticResource cvs}}" /> <DataForm ItemsSource="{Binding Source={StaticResource cvs}}" /> </Grid>

Binding to String Indexers

Silverlight allows targets to be bound to string indexers. This means objects can define custom sets of properties and bind them to UIElements. An object that requires custom properties would expose an indexer that takes a string. This can be done either on the object itself or on a dictionary property. Each entry in the dictionary property represents a custom property. The key in the dictionary describes the name of the property and the value corresponding to that key represents the value of that property. The binding engine supports binding to string indexers, which enables binding to such a dictionary. The XAML below demonstrates how to bind to a string indexer.

XAML

<TextBox Text="{Binding Path=CustomProperties[Nickname]}"/>

The DataContext is an Employee class that has a property named CustomProperties. CustomProperties contains a dictionary of keyed name value pairs.

C#

var emp = new Employee() { FirstName = "John" } emp.CustomProperties.Add("Nickname", "Johnny"); this.DataContext = emp;

The definition for the Employee class shows the CustomProperties property defined as a Dictionary.

C#

public class Employee : INotifyPropertyChanged { private Dictionary<string, Object> _customProps; public Dictionary<string, Object> CustomProperties { get { if (_customProps == null) _customProps = new Dictionary<string, object>(); return _customProps; } } }

TargetNullValue

Silverlight 4 introduces a new binding extension property for TargetNullValue. The TargetNullValue binding extension property applies its value to the target when the source value of the binding operation is Null. The example below will display 0 when the UnitsInStock bound property is Null.

XAML

<TextBox Text="{Binding Path=UnitsInStock, Mode=TwoWay, TargetNullValue=0}" />

StringFormat

In Silverlight 3, values were often formatted by creating a converter class that implements the IValueConverter interface. Silverlight 4 introduces the StringFormat binding extension property that formats a value using either a predefined format or a custom format without the need for a converter class. The examples below show how to format a bound value to a currency and to a percentage, respectively, using the StringFormat feature.

XAML

<TextBox Text="{Binding Path=UnitPrice, Mode=TwoWay, StringFormat=C}" /> <TextBox Text="{Binding Path=Discount, Mode=TwoWay, StringFormat=P}"/>

You can also set the StringFormat to a custom format such as a date format. The example below shows an order date formatted as MM-dd-yyyy (for example: 11-18-2009).

XAML

<TextBox Text="{Binding Path=OrderDate, Mode=TwoWay, StringFormat='MM-dd-yyyy'}"/>

FallbackValue

The FallbackValue binding extension displays a value when the binding operation is unsuccessful. In the example below, the TextBox attempts to bind to a property ManagesEmployees. Assuming that the DataContext is set to a Manager class instance, this property may return a value. However if the DataContext is set to an Employee object that does not have a ManagesEmployees property, the FallbackValue will be displayed instead.

XAML

<TextBox Text="{Binding Path=ManagesEmployees, Mode=TwoWay, FallbackValue=N/A}" />

Databinding Support for Dependency Objects

Silverlight introduces the ability to bind properties on a DependencyObject (DO) and not just on FrameworkElements. For example, in Silverlight you can bind the rotation angle of a RotateTransform to a Slider control using the following XAML:

XAML

<Canvas Width="100" Height="100" RenderTransformOrigin="0.5, 0.5" Background="#FF2B6092"> <Canvas.RenderTransform> <RotateTransform Angle="{Binding ElementName=slider, Path=Value}" /> </Canvas.RenderTransform> </Canvas> <Slider x:Name="slider" Height="20" Margin="0,225,0,55" Minimum="0" Maximum="360" />

The following example shows how to bind the plane projection rotation angles to a series of Slider controls using the new DependencyObject binding feature:

XAML

<Canvas Width="100" Height="100" RenderTransformOrigin="0.5, 0.5" Background="#FF2B6092"> <Canvas.Projection> <PlaneProjection RotationX="{Binding ElementName=sliderX,Path=Value}" RotationY="{Binding ElementName=sliderY,Path=Value}" RotationZ="{Binding ElementName=sliderZ,Path=Value}" /> </Canvas.Projection> </Canvas> <Slider x:Name="sliderX" Height="20" Margin="0,10,0,55" Minimum="0" Maximum="360" /> <Slider x:Name="sliderY" Height="20" Margin="0,30,0,35" Minimum="0" Maximum="360" /> <Slider x:Name="sliderZ" Height="20" Margin="0,50,0,15" Minimum="0" Maximum="360" /> </Canvas>

Also, Silverlight includes a DependencyObjectCollection which provides a way for third parties to define collection properties that contain DependencyObjects and have properties on those DependencyObjects in binding operations.

XPath Support for XML

Silverlight provides the ability to parse XML using a variety of techniques including LINQ to XML and XPath support. XPath support, available in Silverlight 4’s SDK in the System.Xml.XPath.dll, is new to Silverlight 4. It is valuable for those who need to parse XML and already have extensive XPath libraries.

ObservableCollection<T> Constructor Accepts IList and IEnumerable

Silverlight 4 also can take advantage of new constructor overloads that allow it to initialize an ObservableCollection<T> from an IEnumerable or IList. The example below shows a List<string> used to initialize the ObservableCollection<string>.

C#

List<string> ColorList = new List<string> { "red", "blue", "yellow" }; ObservableCollection<string> ColorOC = new ObservableCollection<string>(ColorList);

Isolated Storage Enhancements

Isolated Storage is ideal for storing data on the local client where the Silverlight application can read and write to it. Performance improvements have been made to make accessing data in Isolated Storage faster.

Managed Extensibility Framework (MEF)

The Managed Extensibility Framework (MEF) enables you to build modularized applications whose components (Parts, as MEF calls them) can be added in an incrementally. MEF allows development teams to attach new functionality after the application has been deployed, including while the application is running. MEF allows you to deploy your application in multiple Silverlight applications (XAP) files. This allows the XAP files to be dynamically downloaded at runtime and greatly reduces the startup time of the application. MEF allows applications to be context-aware where the available parts change based on the state of the application. It also improves the general maintainability of your Silverlight applications by greatly reducing coupling between its components. MEF can be used anywhere, anytime within Silverlight development, including within elements created in XAML such as a custom user control. MEF can also be integrated into existing Silverlight applications without the need to rewrite them.

The code sample shows how to extend the Silverlight DataGrid to make it an extensible grid. In the grid, the CompositionInitializer.SatisfyImports static method allows the DataGrid to be composed by MEF through an ambient container. When SatisfyImports is called, a container is created that contains all the exports in the current XAP file. The [ImportMany] attribute tells MEF that it should supply all IGridExtension exports to the grid.

C#

public class ExtensibleDataGrid : DataGrid { public ExtensibleDataGrid() {         CompositionInitializer.SatisfyImports(this); foreach (IGridExtension extension in Extensions) extension.Initialize(this); } [ImportMany] public IEnumerable<IGridExtension> Extensions { get; set; } }

This grid will receive all available IGridExtension exports at runtime. MEF discovers the extensions, creates them, and provides them to the grid. Below is an example of a simple grid extension that makes all fonts in the grid bold. The export attribute tells MEF that the BoldExtension class is a part that offers an export of type IGridExtension.

C#

public interface IGridExtension { void Initialize(DataGrid grid); } [Export(typeof(IGridExtension))] public class BoldExtension : IGridExtension { public void Initialize(DataGrid grid) { grid.FontWeight = FontWeights.Bold; } }

MEF allows you to keep your application decoupled so you can import and export parts as needed. This is ideal for a plug-in model or for simply keeping loosely coupled architecture. MEF can also dynamically load XAP files on demand, which is a great when you have a large application where the XAP size is larger than ideal. The code sample below loads the GridExtensions.xap. Any XAP file can be loaded as long as it is within the same ClientBin folder as the hosting XAP file. Once downloaded, the parts in the XAP are immediately available for import into the application. This is ideal when you have a large modular application.

C#

private void LoadGridExtensions() { var catalog = new DeploymentCatalog("GridExtensions.xap"); catalog.DownloadAsync();     catalog.DownloadProgressChanged +=      new EventHandler<DownloadProgressChangedEventArgs>( catalog_DownloadProgressChanged); catalog.DownloadCompleted += new EventHandler<System.ComponentModel.AsyncCompletedEventArgs>( catalog_DownloadCompleted); }

SDK Enhancements

Assemblies and namespace support have been added to Silverlight 4 to include MEF, frame and navigation refresh enhancements, and the System.Numerics.dll.