Introduction
The first thing to know about Silverlight 5 is that it’s currently in beta, means that it definitely has bugs, and it also not yet feature-complete; some features are going to be shipped later in the final version. In addition, being in beta means that no go-live license available, this is for internal use and testing only so do not install on user’s machine.
Worth mentioning that Silverlight 5 was first announced at PDC 2010 conference (October 2010) and the beta version was shipped later at MIX11 (April 2011,) and the final version will be released soon this year.
Goal
Goals of the version 5 include:
- Improving performance
- Getting closer to WPF
- Enabling line-of-business scenarios
- Better development experience
Improvements
Silverlight 5 has come with lots of improvements and changes, and those improvements can be divided into several areas:
- XAML Changes
- Control and Text Improvements
- Graphics Changes
- Media Changes
- Elevated-Trust Changes
- Performance and Other Improvements
Getting Started
To get started you need to have first Microsoft Visual Studio 2010 Service Pack 1 installed on you PC. After that, you can go to http://silverlight.net and download the beta SDK and tools for VS2010.
In addition, you can install Microsoft Expression Blend Preview for Silverlight 5 Beta if you like using it.
After you have VS2010 SP1 and Silverlight 5 SDK installed on your PC, you can continue reading and start making your cool stuff!
Now let’s start with XAML changes, but first let’s take a look at our model that’s going to be used through all the samples.
XAML Changes
Silverlight 5 has the following changes in the XAML stack:
- Implicit Data Templates
- Ancestor RelativeSource
- Binding in Styles
- Markup Extensions
- XAML Debugging
Let’s see them in action one after one.
Model
Our demos in this section are based on a very simple model consists of just a collection of paper books and audio books. We have the following business model:
public class Book
{
public string Title { get; set; }
public string Author { get; set; }
public decimal Price { get; set; }
}
public class PaperBook : Book
{
public string Isbn { get; set; }
public int Pages { get; set; }
}
public class AudioBook : Book
{
public TimeSpan Duration { get; set; }
}
And here’s our collection:
public class BookData : List
{
public List PaperBooks
{
get
{
return (from b in this where b is PaperBook
select (PaperBook)b).ToList();
}
}
public List AudioBooks
{
get
{
return (from b in this where b is AudioBook
select (AudioBook)b).ToList();
}
}
public BookData()
{
this.Add(new PaperBook()
{
Title = "The Sixth Man",
Author = "David Baldacci",
Isbn = "9780446573108",
Pages = 432,
Price = 14.28m,
});
...
this.Add(new AudioBook()
{
Title = "Water for Elephants",
Author = "Sara Gruen",
Duration = new TimeSpan(11, 29, 00),
Price = 21.56m,
});
}
}
Implicit Data Templates
Silverlight 5 has got one of the great features of data templates in WPF, Implicit Data Templates. Instead of explicitly attaching the data template to every control, you can set a data type (through the DataType property) that the data template will apply to and then the data template will be applied automatically to any control that’s trying to display that data type.
Keep in mind that an implicit data template applies only to controls that…
- Trying to display the data type specified
- Have a templatable content (e.g. collection controls)
- Defined in the scope of the template
So the implicit data template won’t apply to any other control doesn’t meet those requirements
Implementation:
Let’s see implicit data templates in action. In the following scenario we have a list box that uses a data template to display some books and it gets populated through the code:
<ListBox x:Name="books">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Title}" FontWeight="Bold" />
<TextBlock Text="{Binding Author}" />
<TextBlock Text="{Binding Price, StringFormat='C'}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
We could refactor this code by making the data template implicit, and this can be done by moving the data template from the list box to application resources (for instance) and specifying the data type, and then the data template will be applied automatically to each templatable-content control trying to display the data type specified:
<Application.Resources>
<DataTemplate DataType="loc:Book">
<StackPanel>
<TextBlock Text="{Binding Title}" FontWeight="Bold" />
<TextBlock Text="{Binding Author}" />
<TextBlock Text="{Binding Price, StringFormat='C'}" />
</StackPanel>
</DataTemplate>
</Application.Resources>
<ListBox x:Name="books" />
Clear and simple, right?
Now let’s do something more interesting to see the real power of implicit data templates. Instead of having a simple data template, we’ll have two templates for the two types of books, once for the paper books, and the other for the audio books:
<DataTemplate DataType="loc:PaperBook">
<StackPanel>
<TextBlock Text="{Binding Title}" FontWeight="Bold" />
<TextBlock Text="{Binding Author}" />
<TextBlock Text="{Binding Price, StringFormat='C'}" />
<TextBlock Text="{Binding Isbn}" />
<TextBlock Text="{Binding Pages}" />
</StackPanel>
</DataTemplate>
<DataTemplate DataType="loc:AudioBook">
<StackPanel>
<TextBlock Text="{Binding Title}" FontWeight="Bold" />
<TextBlock Text="{Binding Author}" />
<TextBlock Text="{Binding Price, StringFormat='C'}" />
<TextBlock Text="{Binding Duration}" />
</StackPanel>
</DataTemplate>
As you see, each data template will be applied to a templatable-content control that tries to display the data type it specifies. In addition, both the data templates would be applied to a collection control that tries to display a collection of both PaperBook and AudioBook.
Ancestor RelativeSource
This is another feature of XAML that Silverlight 5 has got from WPF. It allows you to bind to a property in a parent control. This is especially useful in situation where you are in a data template and wish to bind to a property in a control outside the template higher in the render tree.
Implementation:
You use {Binding.RelativeSource} to specify the source in the tree.
- Use the AncestorType property to specify the type of the parent control that you wish to bind to.
- Use AncestorLevel to specify how far is the parent control of the type specified from the current control.
The following TextBlock controls all bind to the same
Tag property found in the root
StackPanel:
<StackPanel Tag="Hello, World">
<TextBlock Text="{Binding Tag,
RelativeSource={RelativeSource AncestorType=StackPanel}}" />
<TextBlock Text="{Binding Tag,
RelativeSource={RelativeSource AncestorType=StackPanel, AncestorLevel=1}}" />
<StackPanel>
<TextBlock Text="{Binding Tag,
RelativeSource={RelativeSource AncestorType=StackPanel, AncestorLevel=2}}" />
<Grid>
<TextBlock Text="{Binding Tag,
RelativeSource={RelativeSource AncestorType=StackPanel, AncestorLevel=2}}" />
</Grid>
</StackPanel>
</StackPanel>
And here’s a more complex example. In the following example we change the color of a control inside an item template based on whether the item is selected or not. For this to work we bind to the
IsSelected property of the
ListBoxItem control (that represents an item on the list box) and we use a type converter to return a color based on a Boolean value:
<ListBox x:Name="books">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Title}" FontWeight="Bold"
Foreground="{Binding IsSelected, Converter={StaticResource conv},
RelativeSource={RelativeSource AncestorType=ListBoxItem}}" />
<TextBlock Text="{Binding Author}" />
<TextBlock Text="{Binding Price, StringFormat='C'}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Style Binding
This is another feature of XAML that Silverlight 5 has got from WPF. It allows you to bind directly in style setters, and that would allow changing styles automatically at runtime by changing source objects.
Implementation:
In the following scenario, we have a class that contains brushes used in the application:
public class MyBrushes
{
public SolidColorBrush MainBrush { get; set; }
public MyBrushes()
{
MainBrush = new SolidColorBrush(Colors.Red);
}
}
And we have a style that binds to that class and gets the main brush from there (as you can see, all binding features are available now in style setters):
<loc:MyBrushes x:Key="brushes" />
<Style TargetType="TextBlock">
<Style.Setters>
<Setter Property="FontSize" Value="20" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Foreground"
Value="{Binding MainBrush, Source={StaticResource brushes}}" />
</Style.Setters>
</Style>
Finally, we can change the style automatically at runtime by changing the source brush using code like this:
MyBrushes brshes = Application.Current.Resources["brushes"] as MyBrushes;
brshes.MainBrush.Color = Colors.Red;
Markup Extensions
Markup extensions allow you to execute code at XAML parsing time, they are like {Binding}, {StaticResource}, {RelativeSource}, etc. The new feature of XAML in Silverlight 5 is the ability to create custom markup extensions. They provide more concise syntax, and they are easier and simpler than attached properties.
Implementation:
An example of a very simple markup extension is an extension that sums two numbers and returns the result to the control (the following TextBlock would have the text ‘3’ at runtime):
<TextBlock Text="{my:SumExtension FirstNumber=1, SecondNumber=2}" />
So how to create such an extension? You can create markup extensions by implementing the generic IMarkupExtenstion interface (in System.Xaml namespace) that accepts a type parameter specifies the return type from the extension (must be a reference type.) After that, you provide extension parameters as properties, and you implement ProvideValue() to do the work and return the results to the XAML.
The following code defines our summation extension:
public class SumExtension : IMarkupExtension<object>
{
public int FirstNumber { get; set; }
public int SecondNumber { get; set; }
public object ProvideValue(IServiceProvider serviceProvider)
{
return (FirstNumber + SecondNumber).ToString();
}
}
And here’s a more complex example. In the books scenario, we have defined a markup extension that returns a collection of books based on the book type (paper/audio):
public class BookLocatorExtension : IMarkupExtension<object>
{
public BookType Type { get; set; }
public object ProvideValue(IServiceProvider serviceProvider)
{
if (Type == BookType.Paper)
return BookData.PaperBooks;
else
return BookData.AudioBooks;
}
}
public enum BookType { Paper, Audio }
And here’s how we can use the extension:
<ListBox ItemsSource="{loc:BookLocator Type=Paper}" />
<ComboBox ItemsSource="{loc:BookLocator Type=Audio}" />
XAML Debugging
The last new XAML feature introduced in Silverlight 5 is the ability to debug data bindings. It is very useful when watching for binding errors and it works by placing a breakpoint inside the binding in XAML and watching the Locals window and other Visual Studio windows for binding details.
Keep in mind that XAML debugging works only in Internet Explorer 9 (while enabling debugging from Internet Options.)
Implementation:
In our books scenario, we have the following data form:
<UserControl.Resources>
<loc:BookData x:Key="data" />
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ListBox x:Name="booksList"
DataContext="{StaticResource data}"
ItemsSource="{Binding}" />
<StackPanel Grid.Column="1"
DataContext="{Binding SelectedItem, ElementName=booksList}">
<TextBlock>Title</TextBlock>
<TextBox Text="{Binding Title, Mode=TwoWay}" />
<TextBlock>Author</TextBlock>
<TextBox Text="{Binding Author, Mode=TwoWay}" />
<TextBlock>Price</TextBlock>
<TextBox Text="{Binding Price, StringFormat='C', Mode=TwoWay}" />
</StackPanel>
</Grid>
Now, put a breakpoint inside the binding in the list box and run the application to see what happens.
When you run the application, Visual Studio stops on the breakpoint while it loads the list box with data. Looking at the Locals window we can see binding details:
Here we have the details encapsulated in a BindingState, and the current state is UpdatingTarget means that it’s a Pull operation where list box gets loaded with data.
We can see that we have 5 items in the list referred by FinalSource. In addition, we don’t have any errors or validation errors yet.
Now stop the application, and let’s try something else. Try inserting the breakpoint into the Price text box instead and run the application.
As you can see, Visual Studio stops on both Push and Pull operations. The Pull operation happens when the text box get loaded by the data, and the Push operation happens when the value in the text box changes and gets updated to the source.
Now try writing some invalid data in the price text box (e.g. some letters) and watch the Locals Window:
Now you watch out any error that might happen in binding.
The last thing to mention is that conditions and filters can be used in the breakpoints. As an example, you can use the following condition to tell Visual Studio to stop only on binding errors and not in every operation:
((System.Windows.Data.Debugging.BindingDebugState)BindingState).Error != null
Control and Text Changes
Silverlight 5 has undergone few improvements in controls and text; new added features for controls, and rendering and performance enhancements for text.
The following are the new features of controls in Silverlight 5:
- Text tracking and leading control
- Text overflow
- Multi-click support
- Type-ahead text searching
- SaveFileDialog DefaultFilename
- DataContextChanged event (not in Beta)
And text has been improved in in a few ways:
- Rendering is now better
- Performance of text layout has been improved
- Text clarity is improved with Pixel Snapping
- OpenType support has been enhanced
As improvements in text were all about rendering and performance, we won’t talk more about the text improvements. Instead, we’ll focus in this article on control stack and cover the changes that happened to it in details.
Text Tracking and Leading Control
Silverlight 5 has added three features to text controls (TextBlock, TextBox, and RichTextBox) to allow you to control precisely text tracking and leading space for characters and lines:
- Character Spacing
- Line Height
- Line Stacking Strategy
Character Spacing
This feature allows you to precisely set how far apart each character is. This feature is available in all text controls through a property called CharacterSpacing that specifies the distance between characters. This distance is measured by 1000th of the current font size, means that for instance if you set the font size to 20px and character spacing to 500, then the distance will be 10px between each character (since 20 * 500 / 1000 = 10px.)
Here’s an example of a TextBlock that uses the character spacing feature to put 10px between each character:
<TextBlock FontSize="20" CharacterSpacing="500">
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
</TextBlock>
Line Height
This feature allows you to set precisely the height of each line of the content in a text controls. It’s available in all text controls through a property called LineHeight and, unlike CharacterSpacing, it’s measured in pixels.
The following code sets the height of each line in the text to 50px:
<TextBlock Margin="5" LineHeight="50">
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
<LineBreak />
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
<LineBreak />
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
</TextBlock>
Line Stacking Strategy
This feature allows you to specify how each line box is determined. For example, if you’re in a scenario like the following where you have some text larger than other text, what will you do? Would you increase the height for each line to accommodate the size for the larger text and allow the text to be readable? Or would you leave the text as it as if there wasn’t any text with different font size? That’s what the stacking strategy is all about.
<TextBlock Margin="25" FontSize="12">
Lorem ipsum <Span FontSize="20">dolor sit amet</Span>, ...
<LineBreak />
Proin aliquam augue quis ipsum <Span FontSize="38">rhoncus</Span> ...
<LineBreak />
Quisque eleifend ante vitae velit vehicula luctus. ...
</TextBlock>
The stacking strategy is available to your code through a new property called LineStackingStrategy. This property takes one value of three:
- MaxHeight (default):
Increases the size of each line’s box enough to hold its content. If LineHeight is set, adds the value of LineHeight to the determined value of the height of line’s box.
- BlockLineHeight:
Uses value from LineHeight if specified. Otherwise, increases the size for each line’s box to hold its various font sizes content.
- BaselineToBaseline:
Uses value from LineHeight if sepified. Otherwise, uses the default line height that doesn’t care about whether the content has larger text or not.
The following figure compares between the three stacking strategies while setting LineHeight and while not setting it.
Makes sense?
Text Overflow
This feature allows for multi-column and free-form text layouts. It’s available for RichTextBoxes only. You set a RichTextBox as the master element, and link it to the new RichTextBoxOverflow to capture extra text that doesn’t fit in the master RichTextBox. You can also continue the chain and link another RichTextBoxOverflow to the previous one to capture extra text that doesn’t fit there and so on. To link an overflow control to another one, you use the new OverflowContentTarget property available in the previous control to bind to the next overflow control.
The following figure shows how you can use overflow controls to create multi-column text:
And the following shows an example of a free-form text where the text wraps around an object in the center:
The following example creates a multi-column text:
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<RichTextBox OverflowContentTarget="{Binding ElementName=firstOverflow}" />
<RichTextBoxOverflow x:Name="firstOverflow" Grid.Column="1"
OverflowContentTarget="{Binding ElementName=secondOverflow}"/>
<RichTextBoxOverflow x:Name="secondOverflow" Grid.Column="2" />
Multi-Click Support
Silverlight 5 now allows you to capture multi-clicks in controls. It can capture any n-clicks, but most of the time you’ll capture double-clicks and sometimes triple clicks. This feature is available through a property called ClickCount available in MouseButtonEventArgs. While MouseButtonEventArgs is available in ButtonDown and ButtonUp events, ClickCount is only valid on MouseLeftButtonDown and MouseRightButtonDown, it always return 1 from ButtonUp events.
The following code shows how you can capture multiple clicks in a TextBlock, it updates the TextBlock for each click:
private void theTextBlock_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ClickCount == 1)
theTextBlock.Text += "Single-click\n";
else if (e.ClickCount == 2)
theTextBlock.Text += "Double-clicks\n";
else if (e.ClickCount == 3)
theTextBlock.Text += "Triple-clicks\n";
else
theTextBlock.Text += e.ClickCount.ToString() + "\n";
}
Type-Ahead Text Searching
Type-ahead text searching capability in Silverlight 5 allows you to search in a collection control (e.g. ComboBox, ListBox, etc.) using keyboard; you reach the desired item by typing the first letters of its content.
The content that the control searches in must be specified in DisplayMemberPath. For example, in our books scenario to search in book titles you must set DisplayMemberPath to the Title field. This leads up to another problem, if you have set a data template, you cannot set DisplayMemberPath along with it. This problem can be solved by using the new Silverlight 5 XAML feature, implicit data templates, which has been covered earlier in the previous article.
In our books scenario, we have the following ComboBox that has an implicit data template applied:
<ComboBox x:Name="books" />
And we have also the following code that populates the ComboBox and sets the DisplayMemberPath to allow searching using keyboard:
books.ItemsSource = new BookData().OrderBy(b => b.Title);
books.DisplayMemberPath = "Title";
The application works perfectly now. But if you convert the data template to an explicit data template like the following:
<ComboBox x:Name="books>
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Title}" FontWeight="Bold" />
<TextBlock Text="{Binding Author}" />
<TextBlock Text="{Binding Price, StringFormat='C'}" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
You receive the following error, because DisplayMemberPath cannot be set while setting an ItemTemplate:
SaveFileDialog DefaultFilename
Now in Silverlight 5 you can set the default filename in
SaveFileDialog (using the new
DefaultFileName property) that will show in the file name box when you launch the dialog:
SaveFileDialog dialog = new SaveFileDialog();
dialog.DefaultFileName = "Foo";
dialog.ShowDialog();
DataContextChanged Event
This feature is currently not available in Beta; it should be available in the final version. It occurs when the DataContext object for a control changes.
Graphics Changes
Silverlight 5 has undergone few changes in the graphics stack:
- Improved Performance and Rendering:
Performance has been improved dramatically by using lessons learned from Windows Phone 7. More comes later in this article.
- Hardware Acceleration:
Silverlight 5 now depends more on GPU for graphics processing. This frees CPU from much work, and as a result, improves performance.
- New 3D API:
The most exciting feature yet. Silverlight 5 now supports native 3D API. More comes later.
- Vector Printing:
Very useful for certain cases, not available in the Beta.
- Print Preview:
The long-waited printing feature. Silverlight 5 now allows you to show the user a preview of what he is going to print. Yet not available in the Beta.
Now let’s look at the currently available features in details.
Performance Improvements
To improve rendering performance, Silverlight 5 uses the composition model available in Windows Phone 7. This model implies using a separate, dedicated thread for graphics rendering instead of using the UI thread. This helps freeing the UI thread from graphics work, and thus improves the performance of rendering UI elements and reduces flickers and glitchy animations happen when UI thread was interrupted.
In addition, moving the graphics rendering to another thread adds support for independent animations and helps with immediate-mode rendering on the GPU (in which graphics are sent directly and being rendered on the display.)
3D API
Silverlight 5 now supports natively a 3D API. This API is based on the XNA API; you have the same classes and the same code, however, the 3D API is Silverlight is not game-loop based.
While it’s so amazing to have a 3D API natively supported in Silverlight, things are not as good as they seem. The 3D API of Silverlight 5 is very low-level, means that you have access to the GPU, vertex shaders, and other 3D primitives. It’s not as easy as it should be; it requires that you have a solid understanding of low-level graphics and game development to be able to interact with this API. However, the good news is that community will likely wrap this low-level API into simpler components.
Technically, to draw graphics on the screen you need to use the new control DrawingSurface where all the rendering and graphics go on. This control offers a Draw event that you can use to supply your drawing calls. The calls are carried to a GraphicsDevice object and then be processed and carried to the display.
Because of the complexities in this low-level API, and because we assume that you are a business developer, we won’t discuss the 3D API. Instead, we’ll have a brief look at two of the great samples of this API.
Cube Sample
The cube sample (download from http://bit.ly/sl5-cubesample, colored, non-textured) demonstrates how to create and rotate a 3D cube in Silverlight 5. Here’s a screenshot of this sample:
Looking at the Solution Explorer at project files, we can see that the project contains some pixel shader (PS) and vertex shader (VS) files. Those files besides the HLSL files contain the code (in the HLSL language) for the effects required to render the cube.
Moving to MainPage.xaml you can see the DrawingSurface object used to display the graphics and drawings.
<DrawingSurface Draw="OnDraw" SizeChanged="OnSizeChanged" />
Looking at the code behind at the Draw event handler, we can see that the sample has encapsulated all the code required for drawing the cube and rotating it into a new class called Scene. The Draw event passes the GraphicsDevice object to the Scene to have it draw the cube and other graphics into the device:
Scene scene = new Scene();
public MainPage()
{
InitializeComponent();
}
void OnDraw(object sender, DrawEventArgs args)
{
scene.Draw(args.GraphicsDevice, args.TotalTime);
args.InvalidateSurface();
}
Moving to the Scene class, we can see that it creates another class that handles drawing the Cube, and has configured the view and camera position and completes the drawing in the Draw() function by clearing the screen and calling the Draw() function of the cube.
public class Scene
{
Matrix view; Matrix projection;
Cube Cube = new Cube();
public Scene()
{
Vector3 cameraPosition = new Vector3(0, 0, 5.0f);
Vector3 cameraTarget = Vector3.Zero;
view = Matrix.CreateLookAt(cameraPosition, cameraTarget, Vector3.Up);
}
...
public void Draw(GraphicsDevice graphicsDevice, TimeSpan totalTime)
{
graphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer,
Color.Transparent, 1.0f, 0);
Cube.Draw(graphicsDevice, totalTime, view * projection);
}
}
Finally, the Cube class completes all the drawing by loading the vertex and pixel shaders in its constructor, configuring cube surfaces and surface colors in the CreateCube() function, and then performs the drawing and handling the animation in the Draw() function.
public class Cube
{
static readonly GraphicsDevice resourceDevice
= GraphicsDeviceManager.Current.GraphicsDevice;
VertexShader vertexShader;
PixelShader pixelShader;
public Cube()
{
vertexBuffer = CreateCube();
Stream shaderStream = Application.GetResourceStream(
new Uri(@"CubeSample;component/Cube.vs", UriKind.Relative)).Stream;
vertexShader = VertexShader.FromStream(resourceDevice, shaderStream);
shaderStream = Application.GetResourceStream(...);
,,,
}
VertexBuffer CreateCube()
{
var cube = new VertexPositionColor[36];
Vector3 topLeftFront = new Vector3(-1.0f, 1.0f, 1.0f);
Vector3 bottomLeftFront = new Vector3(-1.0f, -1.0f, 1.0f);
...
return vb;
}
public void Draw(GraphicsDevice graphicsDevice, ...)
{
Matrix position = Matrix.Identity; Matrix scale = Matrix.CreateScale(1.0f);
...
graphicsDevice.SetPixelShader(pixelShader);
graphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 12);
}
}
Lengthy, isn’t it? Now, let’s have a look at another example.
Solar Wind
The Solar Wind 3D sample (download from http://bit.ly/sl5-solarwind) uses the new 3D features of Silverlight 5 to draw the Earth with day and night transitions, atmosphere layers, and population density overlays. It demonstrates advanced concepts and it’s very cool that you’ll like to run and play with it.
Babylon3D
The most amazing sample yet (download from http://bit.ly/sl5-babylon3d), it shows a full 3D realtime engine with some advanced features and an integrated collisions system.
Media Changes
Silverlight 5 has undergone few changes in the media stack:
- Better Battery Management:
Less battery when playing media. Plus, no screensaver in the full-screen mode.
- Remote Control Support:
Now you can control the media being played in Silverlight 5 using a remote control. This feature is currently not available in the Beta.
- Hardware Decoding; More GPU Support:
For better performance, Silverlight 5 depends more on the GPU for media decoding especially for the high definition H.264 formats. In Beta, no DRM or Mac support.
- 1080p Support:
Combined with hardware decoding, user can now watch high definition 1080p media on a Netbook or Tablet.
- IIS Media Services 4:
Support for media streaming using IIS Media Services 4 has been added.
And two more features require more details:
- Speed Control; Trick Play:
Allows you to control playing speed, and to play the media forward or backward.
- Low-Latency Sounds:
Silverlight 5 has added native support for raw wave files.
Speed Control; Trick Play
This feature allows you to control playing speed, to speed-up or slow-down the media. The ability to change playing speed is called, Trick Play. This feature is available in the MediaElement control through a new property called PlaybackRate. This property takes a decimal value ranges from -8, -4, -2, … to …, 0.5, 1.2, 1.4, 2, 4, 8, and the default is 1. The downside of the Beta version is that it doesn’t have a pitch correction, means that when you change the rate to a value other than the default (1) you wouldn’t have any sound. And because of a bug found in the Beta version, you must set this property in code, if you set it in XAML will reset at application start to the default value.
The following are three examples of changing the playing speed of a media element:
media.PlaybackRate = 1.0;
media.PlaybackRate = 4.0;
media.PlaybackRate = -2.0;
Low-Latency Sounds
In the past, you had to create a wave file parser that reads file headers to determine if this is a wave file, and after recognizing a wave file, the parser reads file contents and encode them in order for your application to be able to play it. That changed completely in Silverlight 5. Today, you have native support for raw sounds data (i.e. low-latency sounds.) You can now play wave files and wave data directly in your application without the need to encode them.
This feature is available through a new API based on the XNA Framework. It uses the same classes and functions available in XNA. The main class you have is SoundEffect (Microsoft.Xna.Framework.Audio) that you can use it to play wave files and raw data. You have all the control over the media played; you can set volume, pitch, and stereo space. And you can create a more sophisticated class of SoundEffect called SoundEffectInstance that represents an instance of that sound file. This instance can be played repeatedly, and allows you to have all the control like SoundEffect and more, as we’ll see in the examples.
Finally, keep in mind that Silverlight 5 has the same limitations as XNA; it allows only for 8/16bit PCM, mono/stereo, 22.5/44.1/48khz wave files.
The following code loads the SoundEffect class with a wave file available in application resources:
var resource = Application.GetResourceStream(
new Uri("MediaLowLatency;component/tada.wav",
UriKind.RelativeOrAbsolute));
SoundEffect effect = SoundEffect.FromStream(resource.Stream);
After you have the SoundEffect at your hands, you can call the Play() method to play it. This method have two overrides, one can accept no parameters in which it plays the media normally with the default volume and no changes in the pitch or the stereo space. The other override accepts three values:
- volume:
Ranges from 0.0f to 1.0f.
- pitch:
Ranges from -1.0f to 1.0f. Default is 0f.
- pan:
Controls the stereo space. Ranges from -1.0f to 1.0f. Default is 0f.
The following are some examples of playing sound files using SoundEffect:
effect.Play();
effect.Play(1.0f, 0f, 0f);
effect.Play(1.0f, 1.0f, 0f);
effect.Play(1.0f, -1.0f, 0f);
And finally you can use the SoundEffectInstance to create multiple instances of the same audio, or to play it repeatedly (Volume, Pitch, and Pan values are available through properties):
SoundEffectInstance instance = effect.CreateInstance();
instance.IsLooped = true;
instance.Play();
Elevated-Trust Changes
Elevated-trust applications have undergone few changes in Silverlight 5:
- In-Browser Support
- Multiple Windows Support
- File System Access
- Platform Invocation
Let’s see those changes in details.
In-Browser Support
Unlike previous versions, in Silverlight 5 you don’t have to run your application as OOB to get elevated-trust features, you can now run elevated-trust applications in the browser and get all the features you need.
There’re two security considerations to be taken in order to run your elevated-trust application in browser:
- You must enable running your application in browser via either the Client Access Policy file or the Windows Registry. Using the policy file allows your application to run in a private network. Using the Windows Registry approach allows your application to run on a single machine. In either approaches, you cannot deploy in-browser elevated-trust applications to everyone on the web.
- In addition, your XAP must be signed with a trusted certificate e.g. X.509 certificate) available in the Trusted Publisher Certificate store.
Without any of those requirements, you won’t be able to run your elevated-trust application in browser. But wait, there’s a catch!
In your development machine you can run elevated-trust applications in browser only on whitelisted domains. For example, by default, localhost is whitelisted, so you can easily run an elevated-trust application in the browser in localhost. If you change to another domain, ensure that you add this name to the whitelist, or you won’t be able to run the application. More comes about this later.
The last thing to keep in mind is that in the Beta version, in-browser elevated-trust applications are supported in Windows only. Other platforms are going to be available in the final version.
Client Access Policy Approach
If you want your application to be available in a private network, you need to do some changes to the client access policy file in order to allow it to run in browser as elevated-trust. The changes are as the following; just set the
ElevatedPermissions property of
SecuritySettings to
Required:
<Deployment.OutOfBrowserSettings>
...
<OutOfBrowserSettings.SecuritySettings>
<SecuritySettings ElevatedPermissions="Required" />
<OutOfBrowserSettings.SecuritySettings>
...
</Deployment.OutOfBrowserSettings>
Windows Registry Approach
The other approach you have is to use the Windows Registry to enable in-browser elevated-trust applications to run on a particular machine. To do this, go to
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Silverlight. In this registry key, you have several values related to elevated-trust applications:
- AllowElevatedTrustAppsInBrowser:Set to TRUE (0x00000001) to enable running elevated-trust applications in browser.
- AllowInstallOfElevatedTrustApps:Set to TRUE to enable installation of elevated-trust applications to the PC (i.e. OOB.)
- AllowLaunchOfElevatedTrustApps:Set to TRUE to enable launching elevated-trust applications (in-browser or OOB.)
Example
To run an elevated-trust application in browser you need first to enable OOB and elevated-trust features from project properties. After that, create a Web application and link it to the Silverlight application to host it. If you didn’t do this, your Silverlight application will run as OOB. Your application is able now to run as elevated-trust in browser. To ensure this, you can check for the Application.HasElevatedPermissions property:
theTextBlock.Text = "Is Elevated-Trust: " +
Application.Current.HasElevatedPermissions.ToString();
Now try something more interesting. Try reading a file in the file system that only elevated-trust applications have access to:
theTextBlock.Text =
File.ReadAllText(@"C:\Windows\System32\Drivers\etc\hosts");
As you see, the application works as expected, and has all the elevated-trust features as OOB applications.
Now let’s try changing the domain from localhost to another domain. Go to Web application project properties, switch to the Web tab, then go to Server settings and change the server from Visual Studio Development Server to Local IIS Web Server and use your machine name as the domain and save the settings. (You might be asked to confirm virtual directory creation, it’s because you have changed to another domain and used another virtual directory.)
Now try to run the application. The application won’t be able to run and you’ll get a security exception, that’s because the new domain is not whitelisted like localhost.
Multiple Windows Support
Multiple Windows Support or Ad-hoc Windows is a feature that enables elevated-trust OOB applications in Silverlight 5 to have windows other than the main window. The feature is available through the
Window class which is now instantiable. You use the Window class to create another window and set its contents through the
Content property and show it using the
Visibility property.
The following code creates a Window that’s 400 pixels wide and 300 pixels long, and has just a button in the interface:
Window wnd = new Window();
wnd.Width = 400;
wnd.Height = 300;
wnd.Content = new Button { Content = "Say Hello" };
wnd.Visibility = System.Windows.Visibility.Visible;
Notice that you can end the application by closing the main window; it doesn’t matter if you close any other window.
You’re not limited to just a button or a single object in the window contents. You can create another page (i.e. user control) and set it to be the content of the window:
Window wnd = new Window();
wnd.Width = 400;
wnd.Height = 300;
wnd.Content = new MyOtherPage();
wnd.Visibility = System.Windows.Visibility.Visible;
And you can also create windows with custom chrome by removing the toolbar and borders and create them yourself via code:
Window wnd = new Window();
wnd.Width = 400;
wnd.Height = 300;
wnd.Content = new MyOtherPageWithCustomChrome();
wnd.WindowStyle = WindowStyle.None;
wnd.Visibility = System.Windows.Visibility.Visible;
Notice that if you don’t have elevated-trust features, you won’t be able to spawn other windows. And if you tried to, you’ll get a security exception.
File System Access
Unlike elevated-trust applications in Silverlight 4 which have access to only My Documents folder, Silverlight 5 elevated-trust applications (in-browser and out-of-browser) have full access to the file system. But keep in mind that although you have full access to the file system, you still restricted by the rights of the user running your application. If the user doesn’t have access to a specific file or folder, then you don’t have access to that file or folder.
To test this feature, try reading contents from a file in the system folder (for instance):
theTextBlock.Text =
File.ReadAllText(@"C:\Windows\System32\Drivers\etc\hosts");
As you see, you have access to that file.
By default, if you’re running Windows Vista or Windows 7, your user wouldn’t have administrator privileges as long as he doesn’t launch Visual Studio (or your application) in elevated mode. So if you don’t have admin privileges and tries to gain the write access to the same file your application would fail, that’s because your application is restricted by user rights and the user don’t have write access to that file:
File.AppendAllText
(@"C:\Windows\System32\Drivers\etc\hosts",
"\nfoo");
Same results when trying to write to the system drive without elevated permissions for the user:
File.WriteAllText(@"C:\test.txt", "Foo");
Platform Invocation
Silverlight 4 has introduced support for automation and COM components. Silverlight 5 has added support for Platform Invocation (or P/Invoke.) Platform Invocation allows you to call native code (e.g. DLLs and Windows API) from your Silverlight application. This is a great improvement of course. It uses the same mechanism as other WinForms applications. Unfortunately, this feature is currently not available in the Beta.
Performance and Other Changes
Performance
Performance has been improved in Silverlight 5 in a number of ways:
- Significant improvement in performance through the entire product
- Startup performance has been improved using a multi-core background JIT compiler
- XAML parsing time has been improved especially for UserControl and ResourceDictionary
- Added 64-bit runtime version. Not in beta
- Hardware accelerated rendering in Internet Explorer 9 in windowless mode
Networking
And networking has its share of improvements:
- Network latency has been improved significantly
- 90% performance improvements in ClientHttpWebRequest scenarios
Services
Added support for WS-Trust in WCF. (WS-Trust is a specification aimed to improve security and validation.)
Profiling and Testing
- Automated UI testing
- Improved profiling support:
- Memory
- CPU
- Thread contention
Other
- Support for Windows Azure
- In-Browser HTML support
- Many more fixes and improvements throughout the product