September 2008 - Posts
In Silverlight 2 you can now put up Message Boxes. The call is simple and straight forward and can be made without any input from a user.
This method takes the following three parameters with the last parameters being optional:
- String – The message you want to display
- String – The caption you want to display
- MessageBoxButton – Either MessageBoxButton .OKCancel or MessageBoxButton .OK
It returns a MessageBoxResult which you can use to check which button the user clicked.
Here is an example that displays an initial message, then prompts the user for input on whether to play again:
MessageBox.Show("You won the game!");
MessageBoxResult result = MessageBox.Show("Do you want to play again?", "Restart", MessageBoxButton.OKCancel);
if (result == MessageBoxResult.OK)
{
}
Thank you,
--Mike Snow
Subscribe in a reader
Let’s say a user clicks on a button and you want to popup a separate browser and point them to a specific web page. How do you do this in Silverlight?
Silverlight now supports a method called HtmlPage.PopupWindow(). For security reasons this call can only be made in response to any user input such as a button click.
To use this method you will need to add a reference to System.Windows.Browser;
The call to HtmlPage.PopupWindow() takes three parameters:
- Uri – The location to browse to (I.e http://www.silverlight.net).
- String – The name you want to call the target window.
- HtmlPopupWindowOptions – A variety of options such as window positioning, sizing. Also, whether the toolbar and menubar are visible and more.
The following code demonstrates how to do this in response to a button click from the user:
private void Button_Click(object sender, RoutedEventArgs e)
{
HtmlPopupWindowOptions options = new HtmlPopupWindowOptions();
options.Left = 0;
options.Top = 0;
options.Width = 800;
options.Height = 600;
if(true == HtmlPage.IsPopupWindowAllowed)
HtmlPage.PopupWindow(new Uri("http://www.silverlight.net"), "new", options);
}
*Note: This method is not supported in Safari because it does not implement the right NPAPI contract.
Thank you,
--Mike Snow
Subscribe in a reader
With Silverlight 2 RC0 Silverlight Controls can now be enabled/disabled via the property IsEnabled. This property is supported with all XAML controls found in the toolbox except those controls that are non-interactive (I.e. An ellipse, image, line, etc). By default all controls are enabled so you really only need to add this property if you want to set it to false in order to disable the control.
In addition to the property IsEnabled an event called IsEnableChanged is now available.
When setting IsEnabled=”false” the control is grayed out and will not respond to user interaction.
The following example has two sliders with the first one enabled and the second one disabled:
<Slider Canvas.Top="300" Width="300" Margin="20"></Slider>
<Slider IsEnabled="False" Canvas.Top="340" Width="300" Margin="20"></Slider>
Screen shot:
Thank you,
--Mike Snow
Subscribe in a reader
In the recent release of Silverlight 2 RC0 there is a new event that fires once before the rendering of each frame in your browser. This rendering event is routed to the specified event handler after animation and layout have been applied to the composition tree. In addition, if changes to the visual tree force updates to the composition tree, your event handler is also called.
So, instead of having to use the DispatchTimer or Storyboard Timer, you can now use this new event for your MainGameLoop(). To add the event all you have to do is make a call to:
CompositionTarget.Rendering += new EventHandler(MainGameLoop);
Looking back at our Snowflake demo, the following code was used to create a Storyboard timer to run the main loop:
Storyboard _snowflakeTimer = new Storyboard();
public Page()
{
InitializeComponent();
_snowflakeTimer.Duration = TimeSpan.FromMilliseconds(0);
_snowflakeTimer.Completed += new EventHandler(SnowFlakeTimer);
_snowflakeTimer.Begin();
}
private void SnowFlakeTimer(object sender, EventArgs e)
{
MoveSnowFlakes();
CreateSnowFlakes();
}
The new way to do it would be:
public Page()
{
InitializeComponent();
CompositionTarget.Rendering += new EventHandler(SnowFlakeTimer);
}
private void SnowFlakeTimer(object sender, EventArgs e)
{
MoveSnowFlakes();
CreateSnowFlakes();
}
Thank you,
--Mike Snow
Subscribe in a reader
With the release of Silverlight 2 RC0 there are three new controls we will be discussing that were not available for beta 2. The three new controls with a Tip of the Day for each include:
For this tip we will be exploring the ProgressBar control. The following code below shows how to declare a ProgressBar in your XAML:
<ProgressBar Foreground="White" Background="Gray" Value="25" Maximum="100" Width="200" Height="20" Margin="20">
Let’s take a look at each of these properties in the ProgressBar and what they do:
- Foreground – The color of the acutal bar in the ProgressBar.
- Background – The background color of the control.
- Value – The starting value for the ProgressBar.
- Maximum – The end value for the ProgressBar.
- Width/Height – The width & height of the ProgressBar.
- Margin – The gap between the control and it’s parent container. I find it easier to use Margin over setting Canvas.Left and Canvas.Top.
Add a timer and you can move the progress bar to it’s Maximum value:
namespace Password
{
public partial class Page : UserControl
{
Storyboard _timer = new Storyboard();
public Page()
{
InitializeComponent();
_timer.Duration = TimeSpan.FromMilliseconds(10);
_timer.Completed += new EventHandler(_timer_Completed);
_timer.Begin();
}
void _timer_Completed(object sender, EventArgs e)
{
if (MyProgress.Value < MyProgress.Maximum)
{
MyProgress.Value++;
_timer.Begin();
}
}
}
}
If you run this control as is you will see it start at 25 and end when it’s full:
Begin:
End:
Now if you don’t want to use a timer and want the progress bar to repeat non-stop you can set the the property IsDeterminate to “true”
<ProgressBar IsIndeterminate="True"/>
You can further customize your ProgressBar by setting the Background and Foreground to any of the available brushes:
- Brush
- GradientBrush
- LinearBrush
- Imagebrush
- LinearGradientBrush
- RadialGradientBrush
- SolidColorBrush
Here is an example using an ImageBrush:
<ProgressBar Value="25" x:Name="MyProgress" Maximum="100" Width="300" Height="50" Margin="20">
<ProgressBar.Foreground>
<ImageBrush ImageSource="Smile.png"></ImageBrush>
</ProgressBar.Foreground>
</ProgressBar>
Begin:
End:
Thank you,
--Mike Snow
Subscribe in a reader
If you installed Silverlight 2.0 RC0 with the Blend 2.5 June Preview on the box you will notice the installer blocked on this version of Blend and gave the following error message:
However, on the forums some customers have proceeded to install Blend 2.5 Preview on the box after installing Silverlight 2.0 RC0. These versions are not compatible and if you see the exception EnvDTE.OutputGroup.get_FileCount() in the designer of the Visual Studio tools it is most likely because you have these mismatched product versions.
If you are in this state you can repair your install with these steps:
- Uninstall Blend 2.5 June Preview.
- Uninstall the Microsoft 2 SDK in Add/Remove Programs:
- Re-install the Silverlight Tools.
Note that this release of Silverlight only supports Blend 2.0 with Service Pack 1. The service pack can be downloaded here: A trial of Blend 2 can be found here if you haven’t already purchased it.
Thank you,
--Mike Snow
Subscribe in a reader
With the release of Silverlight 2 RC0 there are three new controls we will be discussing that were not available for beta 2. The three new controls with a Tip of the Day for each include:
For this tip we will be exploring the ComboBox control.
The following code below shows how to declare and size a combo box in your XAML:
<ComboBox Width="100">
<ComboBox.Items >
<ComboBoxItem Content="1st Item"></ComboBoxItem>
<ComboBoxItem Content="2nd Item"></ComboBoxItem>
<ComboBoxItem Content="3rd Item"></ComboBoxItem>
</ComboBox.Items>
</ComboBox>
If you were to run this code you would see a combo box without any selected items:
Click the drop down button and you will see your three items displayed:
If you want to set a default selection for your combo box add the property IsSelected=”true” to any of your ComboBoxItems:
<ComboBox Width="100">
<ComboBox.Items >
<ComboBoxItem Content="1st Item"></ComboBoxItem>
<ComboBoxItem Content="2nd Item"></ComboBoxItem>
<ComboBoxItem IsSelected="True" Content="3rd Item"></ComboBoxItem>
</ComboBox.Items>
</ComboBox>
If you run this code, you will see the 3rd item selected by default:
The ComboBox control also supports data binding. The following code below is an example implementation.
Few notes about this code:
- By setting the DisplayMemberPath property you can specify which data item in your data you want displayed in the ComboBox. In our case below we set this to be the Name. We could have also set DisplayMemberPath =”Price” which would than show the car prices in the ComboBox.
- Setting the SelectedIndex allows you to specify which item in the ComboBox you want selected.
- I have attached an event to detect when the selection in the ComboBox has changed. The SelectedItem member of our ComboBox will return us the car that is selected at any given time.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace Password
{
public partial class Page : UserControl
{
ComboBox _cars = new ComboBox();
public Page()
{
InitializeComponent();
List<Car> carList = new List<Car>();
carList.Add(new Car() { Name = "Ferrari", Price = 150000 });
carList.Add(new Car() { Name = "Honda", Price = 12500 });
carList.Add(new Car() { Name = "Toyota", Price = 11500 });
ComboBox cb = new ComboBox();
_cars.DisplayMemberPath = "Name";
_cars.ItemsSource = carList;
_cars.SelectedIndex = 2;
_cars.SelectionChanged += new SelectionChangedEventHandler(cb_SelectionChanged);
MyCanvas.Children.Add(_cars);
}
void cb_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
Car selectedCar = (Car) _cars.SelectedItem;
int price = selectedCar.Price;
string carName = selectedCar.Name;
}
}
public class Car
{
public string Name { get; set; }
public int Price { get; set; }
}
}
Thank you,
--Mike Snow
Subscribe in a reader
With the release of Silverlight 2 RC0 there are three new controls we will be discussing that were not available for beta 2. The three new controls with a Tip of the Day for each include:
For this tip we will be exploring the PasswordBox control. Password boxes are great in that they hide the characters a user is typing for privacy and security reasons. It is essential to use this control whenever you are receiving a password from a user.
The following code below shows how to declare, size and position a password box in your XAML:
<PasswordBox Canvas.Top="20" x:Name="UserPassword" Width="200"></PasswordBox>
By default Silverlight uses a “dot” as the character to hide the characters the user typed.
You can override this character using the PasswordChar property:
<PasswordBox PasswordChar="*" Canvas.Top="20" x:Name="UserPassword" Width="200"></PasswordBox>
You can also do all this programmatically in your code behind:
PasswordBox passBox = new PasswordBox();
passBox.Width = 200;
passBox.SetValue(Canvas.TopProperty, (double)300);
passBox.PasswordChar = '*';
MyCanvas.Children.Add(passBox);
Note that we have to take the extra step to add it to our Canvas control so that it appears in the element tree.
Thank you,
--Mike Snow
Subscribe in a reader
Version 2 of the Silverlight developer runtime along with the Silverlight Tools is now available. This release candidate will give developers the chance to convert their sites from Beta 2 –> Release before the final release of the runtime is out.
Please check out http://silverlight.net/GetStarted/sl2rc0.aspx for download details that include the developer runtime, Silverlight Tools and Blend.
Also, check out ScottGu’s great blog on this release:
http://weblogs.asp.net/scottgu/archive/2008/09/25/silverlight-2-release-candidate-now-available.aspx
A document detailing the breaking changes between Beta2 and Release can be downloaded here. Below I have outlined a high level overview of the content from this document. If you need further details on a particular breaking change, please refer to the document.
Breaking Change #1. Your Web Page.
If you have a project already developed for beta-1 or beta-2 you will need to make an adjustment to your web page that hosts the Silverlight control. For an HTML page change you will need to change the MIME type. To do this, open your HTML Page, change “x-silverlight-2-b1” or “application/x-silverlight-2-b2” to “application/x-silverlight-2”.
<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%">
If you use an ASPX based Page, open your ASPX page and change the Minimum Version to “2.0.31005.0”:
<asp:Silverlight ID="Xaml1" runat="server" Source="~/ClientBin/TextBlockTest.xap" MinimumVersion="2.0.31005.0" Width="100%" Height="100%" />
Breaking Change #2. ContentPresenter.
ContentPresenter now derives from FrameworkElement instead of Control.
Breaking Change #3. Layout Rendering
Layout no longer causes elements to be rendered at sub-pixel locations. The layout system in Silverlight has been modified to round final measure and arrange values to integers when placing elements on the screen (“pixel snapping”). The result is crisper lines, more consistent rendering look, and fewer rendering artifacts. It is possible that this change will affect how your animations render, in which case you might want to set UseLayoutRounding to false. Also, this change does not affect transforms. If you apply a transform to an element, it may still be rendered at a sub-pixel location.
Breaking Change #4. Cross Domain Hosts.
Cross domain hosts of Silverlight must set the right MIME type for XAP (application/x-silverlight-app)
Breaking Change #5. HttpWebRequest.EndGetResponse()
Exceptions now thrown in HttpWebRequest.EndGetResponse()
Before:
- Some security exceptions (e.g. cross-scheme violations) were being raised in HttpWebRequest.BeingGetResponse()
- All other request error conditions were being returned as 404s.
Now:
- Error conditions are now raised as exceptions in HttpRequest.EndGetResponse().
- Request security errors (e.g. requests not allowed by cross domain policy) raise SecurityExceptions
- Non-successful requests (e.g. those that returned 404s) raise WebExceptions. The WebException.Response is set to HttpStatusCode.NotFound. This is compatible with the desktop.
Breaking Change #6. Font URI
Font URI is Restricted to Assembly Resource. Ensure your font is marked as a "resource" in the project system.
Breaking Change #7. Browser.HtmlElementCollection.
Browser.HtmlElementCollection replaced by Browser.ScriptObjectCollection. Change existing references to HtmlElementCollection to ScriptObjectCollection
Beta 2
HtmlElement myHtmlElement = someOtherHtmlElement.Children[5];
Release
HtmlElement myHtmlElement = (HtmlElement)someOtherHtmlElement.Children[5];
Breaking Change #8. Active Animation
Exceptions When Changing Some Properties on an Active Animation
Breaking Change #9. System.Windows.Controls.Extended.dll
System.Windows.Controls.Extended.dll renamed to System.Windows.Controls.dll. Change all references from System.Controls.Extended to System.Windows.Controls and recompile your application.
Breaking Change #10. VisualStateManager Changes
VisualTransition.Duration has changed to VisualTransition.GeneratedDuration. This value will now only affect the generated transitions, and not the VisualTransition.Storyboard.
Breaking Change #11. KeyDown
KeyDown Sent Synchronously
Breaking Change #12. MeasureOverride/ArrangeOverride
MeasureOverride/ArrangeOverride on Canvas Now Sealed
Breaking Change #13. UriTypeConverter
UriTypeConverter moved to System.dll
Breaking Change #14. HtmlPage.UnregisterScriptableObject
HtmlPage.UnregisterScriptableObject Removed. Developers can now re-use the same script registration key for RegisterScriptableObject. This allows developers to change the underlying managed object associated with a scriptable entry point.
Breaking Change #15. RenderingEventArgs
- RenderingEventArgs is moved from System.Windows to System.Windows.Media
- RenderingEventArgs.ctor() is now internal
- System.Windows.RenderingEventHandler has been removed.
Breaking Change #16. ContentPresenter and ContentControl.
The following properties were removed from ContentPresenter and ContentControl:
- TextAlignment
- TextDecorations
- TextWrapping
Breaking Change #17. FileDialogFileInfo Type and OpenFileDialog.SelectedFile
- The System.Windows.FileDialogFileInfo type is being removed. Its functionality is now being exposed via its base System.IO.FileInfo type to transparent code within Silverlight’s sandbox.
- System.Windows.Controls.OpenFileDialog has a couple properties which consume and expose FileDialogFileInfo. They were modified to return the FileInfo type.
- In addition, the property names SelectedFile and SelectedFiles were also changed to File and Files.
Breaking Change #18. FullAccess Option
The ability for arbitrary scripts to walk the element tree, register for and get notified on events, and use the Silverlight 1.0 Downloader from script has been curtailed in a cross-domain app deployment scenario. The application manifest previously supported the ability for app author to designate the ExternalCallersFromCrossDomain attribute with the values NoAccess (default in cross-domain), ScriptableOnly and FullAccess. Support for the FullAccess option has been removed. Many of the purposes you would have relied on the FullAccess option can now be fulfilled via the Scriptable object feature, with minor additional work on your part.
Breaking Change #19. KeyFrameCollection Changes
Virtual methods Add, Contains, Indexof, Insert, Remove, get_Item, set_Item are no longer declared on the following collections:
- ColorKeyFrameCollection.
- DoubleKeyFrameCollection
- ObjectKeyFrameCollection
- PointKeyFrameCollection
- PointKeyFrameCollection
- StrokeCollection
Breaking Change #20. Request stream
You must close the request stream on an HttpWebRequest before calling BeginGetResponse(). Previously BeginGetResponse() would close an open request stream.
Breaking Change #21. HtmlWindow references on Safari/Mac
HtmlWindow references on Safari/Mac will no longer evaluate to true.
Breaking Change #22. WebClient EventArg
Address property removed from all WebClient EventArg classes
Breaking Change #23. Constructors Made Internal
You can no longer create the objects listed below because their associated constructors have been made internal:
- SizeChangedEventArgs
- TextChangedEventArgs
- DownloadProgressEventArgs
- ExceptionRoutedEventArgs
- KeyEventArgs
- MouseButtonEventArgs
- MouseEventArgs
- StartupEventArgs
- Expression
- GeneralTransform
- Geometry
- ImageSource
- PathSegment
- SetterBase
- Transform
- BindingExpressionBase
- InputMethod
Breaking Change #24. System.Xml exception type
In the methods/constructors shown below, we will no longer be checking for null arguments. As a result, the usage of null arguments will result in a NullReferenceException. In previous builds of Silverlight, use of a null argument would result in an ArgumentNullException being thrown. There is no change in functionality, just the type of exception that is being thrown.
- XmlReader.IsName method
- XmlReader constructor
- XmlReader.MoveToAttribute method
- XmlReader:IsNameToken method
- XmlNamespaceManager constructor
- XmlReader.Nametable.Add method
- XmlReader.Nametable.Get method
- XmlCharCheckingWriter.WriteQualifiedName method
- XmlCharCheckingWriter.WriteDocType method
- XmlConvert.ToBoolean method
- XmlConvert.ToDouble method
- XmlConvert.ToSingle method
- XmlConvert.ToDateTime method
Breaking Change #25. Accessible constructors
Cannot create classes in XAML that do not have accessible constructors
Breaking Change #26. AG_E_UNKNOWN_ERROR
In previous versions of Silverlight, when media failed because a media file was not available, a MediaFailed event was fired but if the MediaFailed event was not handled by the developer, the end user would not be notified of the failure. Now when a handler is not hooked up to the MediaFailed event, the error bubbles up to the default OnError handler of the plug-in and AG_E_UNKNOWN_ERROR is displayed to the user.
Fix Required: Attach the MediaFailed event to your MediaElement objects and handle errors as appropriate.
Breaking Change #27. Generic.xaml resource dictionary
Platform looks for generic.xaml as a resource at themes/generic.xaml
Breaking Change #28. HTTP Polling Duplex OM Changes and Reengineering
- PollTimeout setting on the server side (PollingDuplexHttpBinding and PollingDuplexBindingElement) has been renamed to ServerPollTimeout
- PollTimeout setting on the PollingDuplexBindingElement (client side) has been renamed to ClientPollTimeout.
- PollTimeout setting on the PollingDuplexHttpBinding (client side) has been cut. In most scenarios, it should not be necessary to change this. If a change is necessary, it can be achieved through the ClientPollTimeout on the PollingDuplexBindingElement.
- Client-side support has been cut from the non-Silverlight (server-side) polling duplex assembly (i.e. BuildChannelFactory will throw a NotSupportedException). That is, in RTM, the client side for polling duplex must be Silverlight (and the server side must be the regular .NET Framework, but this restriction was already in place in Beta2).
- Default timeouts have been changed for the Duplex channel. For most common scenarios, the new out-of-the-box defaults should be appropriate and there is no need to change them.
- An error (404) on a polling request will cause the duplex channel to fault.
- Various invalid messages used to be ignored by the Duplex stack but will now be rejected.
- If any HTTP error (404,500,…) is encountered during a SOAP call, a CommunicationException is now thrown instead of a ProtocolException.
Breaking Change #29. IXcpControl COM interface
The following splash screen related properties added to IXcpControl interface are being broken out and being moved to a new IXcpControl2 interface:
- get_OnSourceDownloadComplete
- get_OnSourceDownloadProgressChanged
- get_SplashScreenSource
- put_OnSourceDownloadComplete
- put_OnSourceDownloadProgressChanged
- put_SplashScreenSource
Breaking Change #30. Content-Type is allowed on cross domain request by default
Both supported cross domain policy files (crossdomain.xml, clientaccesspolicy.xml) no longer need to explicitly allow the Content-Type request header. The Content-Type header is always settable on POST xdomain requests, as long as the request itself is allowed by a cross domain policy file.
In addition, the LoadRuntime function is also being moved to IXcpControl2.
Breaking Change #31. Delegate type check
f you want to combine two delegate objects they should be of the exact same delegate type.
Breaking Change #32. Miscellaneous API Changes
- UIElement.HitTest method has moved to the VisualTreeHelper class and renamed to VisualTreeHelper.FindElementsInHostCoordinates.
- Moved DependencyPropertyChangedEventHandler delegate type from System.Windows.Controls to System.Windows namespace.
- Control.IsTabStop defaults to true. Now, all Control derived classes (directly or indirectly) have IsTabStop set to true except, UserControl, HyperlinkButton, ScrollViewer and ListBox.
- WebHeaderCollection.Keys property was replaced with the AllKeys property.
- WebHeaderCollection.Headers property was renamed to Keys.
- WebRequest.RegisterPrefix() now returns false in failure cases per the interface contract from the desktop framework rather than throwing an exception.
- WebResponse.Dispose(bool explicitDisposing) was removed.
- Deployment.PartProperty is now read only.
- Deployment.EntryPointAssemblyProperty is now read only.
- Deployment.EntryPointTypeProperty is now read only.
- Deployment.RuntimeVersionProperty is now read only.
- Deployment.ExternalCallersFromCrossDomainProperty is now read only.
- Thumb.IsDragging is now read only.
- Slider.IsFocused is now read only.
- ButtonBase.IsFocused is now read only.
- ButtonBase.IsMouseOver is now read only.
- ButtonBase.IsPressed is now read only.
- ToolTipService.GetToolTip is now private.
- IRawElementProviderSimple is now sealed and has a private default constructor.
- Setter.PropertyProperty is now internal. Please use the CLR property instead of the DependencyProperty.
- Slider.UpdateTrackLayout() is now internal.
- Slider.OnOrientationChanged() is now internal.
- Slider.OnIsFocusChanged(DependencyPropertyChangedEventArgs e) is now internal.
- ComboBox.get_IsSelectionActive() is now internal.
- ComboBox.ScrollIntoView(Int32 index) is now internal.
- ComboBox.get_SelectionBoxItemTemplate() now returns System.Windows.DataTemplate.
- PasswordBox.SelectionChanged is now private.
- MouseEventArgs.Handled was moved to MouseButtonEventArgs.
- RenderTargetBitmap was renamed to HostingRenderTargetBitmap and moved from System.Windows.Media.Imaging to namespace System.Windows.Interop.
- AutomationPeer constructor is now protected.
- TriggerActionCollection.Item now takes System.Windows.TriggerAction instead of System.Windows.Media.Animation.BeginStoryboard.
- TriggerCollection.Item now takes System.Windows.TriggerBase instead of System.Windows.EventTrigger.
- RoutedEventArgs.Source was renamed to OriginalSource and is now read-only.
- ITableItemProvider and ITableProvider are now derived from IGridItemProvider and IGridProvider.
- The KeyboardNavigation class is now internal.
- ColumnDefinitionCollection constructor was made internal.
- InlineCollection constructor was made internal.
- ItemCollection constructor was made internal.
- RowDefinitionCollection constructor was made internal.
- UIElementCollection constructor was made internal.
- TriggerCollection constructor was made internal.
- Listbox field ListBoxItem._itemsControl is now internal.
- Ink.Stroke constructor changed to ctor(System.Windows.Input.StylusPointCollection).
- CanConvertFrom(Type sourceType) changed its signature to CanConvertFrom(ITypeDescriptorContext context, Type sourceType).
- CanConvertTo(Type destinationType) changed its signature to CanConvertTo(ITypeDescriptorContext context, Type destinationType).
- ConvertFrom(object value) changed its signature to ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value).
- ConvertFromString(string text) now is ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) where value of type string.
- ConvertTo(object value, Type destinationType) changed its signature to ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType).
- ConvertToString(object value) now is ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) with destinationType of type string.
- ItemCollection constructor is no longer available so any code that tries to instantiate an ItemCollection directly will no longer compile. This class is supposed to be instantiated only within ItemsControl.
- ContentPresenter now derives from FrameworkElement instead of Control.
- Control.OnIsEnabledChanged was removed. Now use IsEnabledChanged for extended controls.
- DownloadProgressEventHandler was removed.
- The following converters were removed:
- TextDecorationCollectionConverter
- FontStretchConverter
- FontStyleConverter
- FontWeightConverter
- FontFamilyConverter
Thank you,
--Mike Snow
Default Fonts
By Default, Silverlight supports the following local fonts (as shown rendered in Silverlight):
You can also choose from a long list of East Asian fonts if they are available on your local computer:
- Batang
- BatangChe
- DFKai-SB
- Dotum
- DutumChe
- FangSong
- GulimChe
- Gungsuh
- GungsuhChe
- KaiTi
- Malgun Gothic
- Meiryo
- Microsoft JhengHei
- Microsoft YaHei
- MingLiU
- MingLiu_HKSCS
- MingLiu_HKSCS-ExtB
- MingLiu-ExtB
- MS Gothic
- MS Mincho
- MS PGothic
- MS PMincho
- MS UI Gothic
- NSimSun
- NSimSun-18030
- PMingLiU
- PMingLiu-ExtB
- SimHei
- SimSun
- SimSun-18030
- SimSun-ExtB
Custom Fonts
In addition to the default fonts users can use their own custom made or purchased fonts. Make certain you have the legal rights to using these fonts in your application.
The steps you need to take to import and use a custom font are:
- Right click on your Silverlight application project folder in the Solution Explorer, choose “Add->New Item…”
- Browse to your font, select it and click the OK button.
- Select the font, in the property grid set the Build Action = “Resource” and the “Copy to Output Directory” = “Copy if newer”:
- Now, in your XAML, in order to reference the font in an element like a TextBlock use the following syntax in the attribute FontFamily as highlighted in yellow below - FontFamily=”[FontFileName]#[FontFriendlyName]”
Example: <TextBlock Text="Hi" FontFamily="Century.ttf#Century"></TextBlock>
- To get the exact name of the font just double click on the font in the solution explorer to open the font viewer:
Supported Types.
The following types of user added fonts are supported: TTF, ODTTF and OTF. Silverlight will not recognize other font types such as FON and TTC that are added by a user. If, however, the system has these fonts already installed they will be recognized.
Additional Notes
You may have noticed from Tip of the Day #45 that Silverlight provides an option for text called FontStretch that allows you to stretch the font. However, when applied to normal fonts like “Arial”, “Verdana”, “Times New Roman”, etc you might notice that nothing happens. This is because Silverlight does not do any stretch emulation. This option must be applied to fonts that specifically support it such as Adobe Open type (OTF) fonts.
Thank you,
--Mike Snow
Subscribe in a reader
Silverlight comes with a very useful control called TextBlock. This control allows you to render read only text. Displaying text via this control is as easy as:
<TextBlock Text="Hello There"></TextBlock>
There are also a variety of options you can apply to your font. These include:
1. FontFamily. The font typeface family name.
<TextBlock FontFamily="Courier New">Hello There</TextBlock>
<TextBlock FontFamily="Times New Roman" Canvas.Top="10">Hello There</TextBlock>
<TextBlock FontFamily="Verdana" Canvas.Top="20">Hello There</TextBlock>
2. FontSize. The font size in pixels.
<TextBlock FontSize="10">Hello There</TextBlock>
<TextBlock FontSize="20" Canvas.Top="20">Hello There</TextBlock>
<TextBlock FontSize="30" Canvas.Top="50">Hello There</TextBlock>
2 FontStetch. Options include:
Note that the support for the above options will depend upon the font you are using.
3 FontWeight. Options include: Thin, ExtraLight, Light, Normal, Medium, SemiBold, Bold, ExtraBold, Black, ExtraBlack.
Note that the support for the above options will depend upon the font you are using.
<TextBlock Text="Hello There" FontWeight="Normal" Canvas.Top="0"></TextBlock>
<TextBlock Text="Hello There" FontWeight="Bold" Canvas.Top="10"></TextBlock>
4 FontStyle: Options include: Normal, Italic
<TextBlock Text="Hello There" FontStyle="Normal" Canvas.Top="0"></TextBlock>
<TextBlock Text="Hello There" FontStyle="Italic" Canvas.Top="10"></TextBlock>
5. Foreground. This allows you to change the color of the font. You can use brushes including solid color, gradient, image or video brushes to create a wide variety of effects.
<TextBlock Text="Hello There" FontSize="20" FontFamily="Arial" Canvas.Top="0"> <TextBlock.Foreground>
<LinearGradientBrush>
<GradientStop Color="#FF0000FF" Offset="0.0" />
<GradientStop Color="#FFEEEEEE" Offset="1.0" />
</LinearGradientBrush>
</TextBlock.Foreground>
</TextBlock>
<TextBlock Text="Hello There" FontSize="20" FontFamily="Arial" Canvas.Top="20" Foreground="Red"></TextBlock>
6. TextDecorations. A text decoration is a visual ornament that you can add to text. Currently the only supported decoration is underline.
<TextBlock TextDecorations="underline">Hi there</TextBlock>
7. Runs. Last, you can inter-mix different runs of text formatting within the same block using the Run element. For example, you can display a string like this:
<TextBlock>
<Run FontWeight="Bold">Hello There.</Run>
<Run Foreground="Red">How are you?</Run>
<Run FontStyle="Italic">I am fine thanks!</Run>
<Run>漢字</Run>
</TextBlock>
Thank you,
--Mike Snow
Subscribe in a reader
In Tip of the Day #42 I talked about how to create and use a web service using WCF for your Silverlight application. For this tip I would like to briefly discuss WCF and some highlights on why you should use it over the traditional ASMX based Web Services. Also, I will be touching on what Silverlight-enabled WCF services gives you.
Highlights and Advantages of WCF:
- WCF stands for “Windows Communication Foundation”.
- WCF is Microsoft’s next generation platform for network distributed services that shipped as part of the .NET 3.0 framework. Call it the successor and unifier of most distributed systems out there today.
- WCF runtime resides under the System.ServiceModel namespace.
- In most cases WCF is significantly more performant (25%-50%) faster. See this MSDN article for comparisons.
- The throughput of WCF is inherently scalable from a single processor to a quad processor.
- The WCF model unifies the feature wealth of ASMX, WSE, Enterprise Services, MSMQ, and Remoting. This way, developers only have to master a single programming model.
- WCF can be hosted in IIS Servers, Windows services and standalone apps like windows forms, console apps.
- WCF provides a DataContractSerializer which allows complex data types and private attributes to be serialized and sent.
- WCF can have messages sent in a variety of channels including HTTP, TCP, MSMQ, Named pipe, etc.
The list goes on but hopefully this gives you a good starting point into why you should use WCF over traditional web services.
When adding a WCF service to your web site for Silverlight, make certain to choose “Silverlight-enabled WCF service” over the standard “WCF Service”. Since WCF is the best practice for writing services with Silverlight, Microsoft has provided this template as a way to get you a service that is already configured in a specific way for Silverlight. Primarily what is done for you is:
- Web.config is configured to use basicHttpBinding since Silverlight does not support ws*.
- ASP compatibility mode: <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
Thank you,
--Mike Snow
Subscribe in a reader
I am not a big fan of winter, being that summer is my favorite season. However, this morning I woke up and heard it’s going to be snowing in the mountains (Cascades) so it inspired me to have a little premature fun by creating a snowy scene in Silverlight.
Demo:
Screenshot:
To the right of the demo is a toolbar that allows you to:
- Adjust the volume of snow.
- Adjust the wind speed (left-right).
I noticed the application was a lot less performant on a beta 2 build then on an RTM build. So, if you are using beta 2 I would recommend caution when increasing the volume of the snow.
To make this demo follow these steps:
Step 1. Create a Silverlight Application Project using Visual Studio 2008. (See Tip of the Day #2 for details).
Step 2. Add the following images to your Silverlight Application project:
Step 3. Add a new Silverlight User Control to your Silverlight Application and call it SnowFlake.xaml. To do this, right click on your Silverlight application node in the Solution Explorer. Choose “Add->New Item…”. Select “Silverlight User Control” changing the Name to “Snowflake.xaml” and hit the OK button.
Step 4. Change the XAML of your Snowflake.xaml control to the following.
<UserControl x:Class="Snowflakes.SnowFlake"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Image x:Name="Flake" Source="snowflake.png">
<Image.RenderTransform>
<ScaleTransform x:Name="SnowScale" ScaleX="0.25" ScaleY="0.25"></ScaleTransform>
</Image.RenderTransform>
</Image>
</UserControl>
We are essentially adding a single image to represent a snowflake. Since the original snowflake image is bigger than I wanted, I have scaled it to 0.25 (1/4) its original size by using a ScaleTranform.
Step 5. In the code behind of the snowflake (Snowflake.xaml.cs) we will add the logic needed to make the snowflake fall. Essentially what we are doing is:
- Track the Left, Top coordinates of the snowflake. The snowflake has a random 1 in 50 chance of changing direction.
- When the snowflakes Top coordinate equals the floor value (764 in my images case), or when it goes off the screen we set Completed = true. Our main timer loop in Page.xaml.cs will go through and clean up all snowflakes with Completed set to true.
- When we create the snowflake we randomly scale it up or down a little to give an added depth perception.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace Snowflakes
{
public partial class SnowFlake : UserControl
{
double _posLeft = 0.0;
double _posTop = 0.0;
double _floorValue = 764;
int seed = DateTime.Now.Millisecond;
Random _rand = new Random(DateTime.Now.Millisecond);
private bool _completed = false;
double _horzInc = 0.0;
public bool Completed
{
get { return _completed; }
}
public SnowFlake(double left, double top)
{
InitializeComponent();
_posLeft = left;
_posTop = top;
this.SetValue(Canvas.LeftProperty, _posLeft);
this.SetValue(Canvas.TopProperty, _posTop);
Random rndSize = new Random(DateTime.Now.Millisecond);
SnowScale.ScaleX = SnowScale.ScaleY = 0.05 * rndSize.Next(1, 6);
}
public void Fall(double windValue)
{
int value = _rand.Next(50);
if (value == 25) // 1 in 50 change to change direction
{
if (_horzInc >= 0.2)
_horzInc = 0;
else if (_horzInc <= -0.2)
_horzInc = 0;
else
{
value = _rand.Next(3);
if (value == 1) _horzInc = 0.2;
else if (value == 2) _horzInc = -0.2;
else if (value > 0) _horzInc = 0.0;
}
}
double horzValue = _horzInc + (windValue * 0.1);
_posLeft += horzValue;
this.SetValue(Canvas.LeftProperty, _posLeft);
this.SetValue(Canvas.TopProperty, _posTop++);
_completed = (_posLeft >= 1019 || _posLeft <= 0 || _posTop >= _floorValue);
}
}
}
Step 6: Back in Page.xaml.cs we add a timer to move and create the snowflakes. When moving the snowflakes, we check to see if the snowflake has Completed = true. If so, we add it to an array for removal. When creating the snowflakes, we create them along the top of the page. However, if there is wind we also need to create them to the left or to the right of the scene as well depending on the wind direction.
The following is the code for Page.xaml.cs including the code needed to handle the toolbar:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace Snowflakes
{
public partial class Page : UserControl
{
List<SnowFlake> _snowFlakes = new List<SnowFlake>();
Storyboard _snowflakeTimer = new Storyboard();
Random _rand = new Random(DateTime.Now.Millisecond);
int _newFlakeCount = 2;
int _wind = 0;
public Page()
{
InitializeComponent();
_snowflakeTimer.Duration = TimeSpan.FromMilliseconds(10);
_snowflakeTimer.Completed += new EventHandler(SnowFlakeTimer);
_snowflakeTimer.Begin();
}
private void SnowFlakeTimer(object sender, EventArgs e)
{
MoveSnowFlakes();
CreateSnowFlakes();
}
private void MoveSnowFlakes()
{
List<SnowFlake> _flakesToRemove = new List<SnowFlake>();
foreach (SnowFlake flake in _snowFlakes)
{
flake.Fall(_wind);
if (true == flake.Completed)
_flakesToRemove.Add(flake);
}
foreach (SnowFlake flake in _flakesToRemove)
{
_snowFlakes.Remove(flake);
SnowCanvas.Children.Remove(flake);
}
_snowflakeTimer.Begin();
}
private void CreateSnowFlakes()
{
TotalCount.Text = "Total Snowflakes = " + _snowFlakes.Count;
int count = _rand.Next(0, _newFlakeCount);
for (int i = 0; i < count; i++)
{
SnowFlake flake = new SnowFlake(_rand.Next(0, 1020), 0.0);
_snowFlakes.Add(flake);
SnowCanvas.Children.Add(flake);
}
if (_wind < 0)
{
for (int i = 0; i < count; i++)
{
SnowFlake flake = new SnowFlake(1010, _rand.Next(0, 700));
_snowFlakes.Add(flake);
SnowCanvas.Children.Add(flake);
}
}
else if (_wind > 0)
{
for (int i = 0; i < count; i++)
{
SnowFlake flake = new SnowFlake(0, _rand.Next(0, 700));
_snowFlakes.Add(flake);
SnowCanvas.Children.Add(flake);
}
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Application.Current.Host.Content.IsFullScreen = true;
}
private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
if (null != Volume)
{
_newFlakeCount = (int)Volume.Value;
VolumeValue.Text = _newFlakeCount.ToString();
}
}
private void Wind_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
if (null != Wind)
{
_wind = (int)Wind.Value;
WindValue.Text = _wind.ToString();
}
}
}
}
Step 7: The following is the toolbar code we put in Page.xaml:
<UserControl x:Class="Snowflakes.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="1020" Height="768">
<Canvas x:Name="SnowCanvas" Width="1020" Height="768" Background="Black">
<Image Width="1020" Source="Scene.jpg"></Image>
<TextBlock Canvas.Left="1022" x:Name="TotalCount" Foreground="White">Total Snowflakes</TextBlock>
<TextBlock Canvas.Left="1022" Canvas.Top="30" Foreground="White">Volume</TextBlock>
<Slider x:Name="Volume" Value="3" ValueChanged="Slider_ValueChanged" Canvas.Left="1110" Canvas.Top="30" Minimum="0" Maximum="10" Width="100"></Slider>
<TextBlock Canvas.Left="1210" Canvas.Top="30" Foreground="White" x:Name="VolumeValue">2</TextBlock>
<TextBlock Canvas.Left="1022" Canvas.Top="60" Foreground="White">Wind</TextBlock>
<Slider x:Name="Wind" Value="0" ValueChanged="Wind_ValueChanged" Canvas.Left="1110" Canvas.Top="60" Minimum="-50" Maximum="50" Width="100"></Slider>
<TextBlock Canvas.Left="1210" Canvas.Top="60" Foreground="White" x:Name="WindValue">0</TextBlock>
<Button Canvas.Left="1022" Canvas.Top="100" Content="Full Screen" Click="Button_Click"></Button>
</Canvas>
</UserControl>
With that, you have a beautiful snowy scene to enjoy!
Thank you,
--Mike Snow
Subscribe in a reader
Web services are essentially API’s that can be accessed over a network such as the Internet. Due to security Silverlight restricts a lot of important features such as saving to the disk. However, you can get around these restrictions by making calls to web services instead to accomplish these features.
This Tip of the Day will step you through how to create a web service in your web site and I will show you how to reference and make calls to API’s in that web service.
Step 1. Create a Silverlight Application Project using Visual Studio 2008. (See Tip of the Day #2 for details).
Step 2. Add a Web Service to your Web Site.
- In your Solution Explorer, right click on your Web Site node, Choose Add-> New Item…
- There are 3 templates that offer Web Service functionality:
- Silverlight-enabled WCF Service.
- WCF Service
- Web Service.
Choose “Silverlight-enabled WCF Service” as it has specific support for Silverlight which we will explore in our next Tip of the Day.
- Change the name to something like “MyService.asmx” and click the “Add” button.
Step 3. Add a Service Reference
- Rebuild your Solution (Ctrl+Shift+B). If you proceed to the next bullet point without rebuilding you will get the following dialog:
- In your solution explorer, right click on your Silverlight Application node and choose “Add Service Reference…”.
- This will bring up the “Add Service Reference” dialog. Click the “Discover” button to find your web service.
- Change the Namespace to be whatever you want for this reference and click the “OK” button.
At this point you have your web service setup that is properly referenced from your Silverlight application.
Step 4. Making a call from your Silverlight application into your web service.
- In your Solution Explorer, from your web site open up MyService1.svc. By default there is one method made available called DoWork(). This doesn’t do much yet so let’s add a new function called HelloWorld() that will return a string. Make certain to include the [OperationContract] attribute in order to make this function visible:
[OperationContract]
public string HelloWorld()
{
// Add your operation implementation here
return "Hello World";
}
- In your Silverlight application project under your Service References, right click on ServiceReference1 and choose “Update Service Reference”.
- Next, let’s make a call from our Silverlight app to this HelloWorld() method. The following code which goes in Page.xaml.cs shows you how to make an async call to HelloWorld().
public partial class Page : UserControl
{
public Page()
{
InitializeComponent();
ServiceReference1.MyService1Client client = new SilverlightApplication9.ServiceReference1.MyService1Client();
client.HelloWorldCompleted += new EventHandler<SilverlightApplication9.ServiceReference1.HelloWorldCompletedEventArgs>(client_HelloWorldCompleted);
client.HelloWorldAsync();
}
void client_HelloWorldCompleted(object sender, SilverlightApplication9.ServiceReference1.HelloWorldCompletedEventArgs e)
{
string message = e.Result;
}
}
Note that all web services calls must be done asynchronously.
Thank you,
--Mike Snow
Subscribe in a reader
Bookmarks are very useful in web sites because they allow people to directly navigate back to a section of the web site they visited before. This tip will show you how to apply and use bookmarks in Silverlight applications.
For example, if a user types in http://www.MySilverlightApp.com/default.aspx#Page2 you would intercept this from the address bar and show the second page of your application.
For our demo, for simplicity sakes, we will just make each page it’s own Canvas element with a TextBlock. Ideally you would probably want to make each page its own UserControl. I have created two pages: Page1 and Page2.
Page.xaml:
<UserControl x:Class="SilverlightApplication14.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<Canvas>
<Canvas x:Name="Page1">
<TextBlock>Hello there this is page 1</TextBlock>
</Canvas>
<Canvas x:Name="Page2" Visibility="Collapsed">
<TextBlock>Hello there this is page 2</TextBlock>
</Canvas>
</Canvas>
</UserControl>
In the constructor of Page.xaml.cs we call ProcessBookmark(). This routine will get the bookmark string from the address bar by calling HtmlPage.Window.CurrentBookmark; Once we know what the bookmark is we can set the Visiblity of the Canvas we want displayed to Visible. Note that we also set the title bar of the browser window by calling HtmlPage.Document.SetProperty("title", _page1Title);
public partial class Page : UserControl
{
const string _page1Title = "My Silverlight App - Page 1";
const string _page2Title = "My Silverlight App - Page 2";
public Page()
{
InitializeComponent();
ProcessBookmark();
}
private void ProcessBookmark()
{
string bookMark = HtmlPage.Window.CurrentBookmark;
switch (bookMark)
{
case "Page1":
HtmlPage.Document.SetProperty("title", _page1Title);
Page1.Visibility = Visibility.Visible;
Page2.Visibility = Visibility.Collapsed;
break;
case "Page2":
HtmlPage.Document.SetProperty("title", _page2Title);
Page1.Visibility = Visibility.Collapsed;
Page2.Visibility = Visibility.Visible;
break;
}
}
}
So what if you want to set the address bar to a bookmark? You can change the string in the address bar of your browser with the following call: HtmlPage.Window.Eval("window.location.hash='Page1'");
More specifically:
1: private void SetBookmark(string bookmark)
2: {
3: HtmlPage.Window.Eval("window.location.hash='"+bookmark+"'");
4: }
Currently if you hit the back button in your browser it will exit you out of your Silverlight. I am looking into a way to intercept the Back and Forward buttons in your browser so that we can create a history of bookmarks internal to our Silverlight application. If anyone has some good resources/techniques let me know and I will incorporate the functionality into this blog.
Thank you,
--Mike Snow
Subscribe in a reader
Next