sticky
Silverlight General FAQ RRS feed

  • Question

  • 1. General:

    1.1 What is the purpose of this FAQ?

    1.2 What is Silverlight and how do I get started with Silverlight?

    2. XAML:

    2.1 What is namescope?

    2.2 What should I remember when using XamlReader to create objects dynamically?

    3. Web Service:

    3.1 What is the cross domain/scheme/zone policy? How do I configure it?

    3.2 How do I provide a cross domain policy file for a self-host WCF service?

    3.3 How do I call a web service without a proxy?

    3.4 What are the restrictions of web service accessing in Silverlight 2?

    4. Graphics:

    4.1 What graphic related features are supported in Silverlight 2?

    4.2 How do I create 3D effect?

    5. Animation:

    5.1 How do I create animation without Storyboard?

    5.2 How do I create a Storyboard and apply it to multiple elements?

    5.3 What’s the difference between animation in Flash and Silverlight?

    6. Multimedia:

    6.1 What media types are supported in Silverlight 2?

    6.2 How do I modify the media player generated by Expression Encoder 2?

    6.3 How do I open and play a local media file?

    7. Data:

    7.1 What data binding features of WPF are not yet supported in Silverlight? Is there a workaround?

    7.2 How do I bind to flexible (untyped) data sources?

    8. Socket:

    8.1 What is the socket accessing policy? How do I create a socket policy server?

    9. Html and ASP.NET integration:

    9.1 How do I use InitParams?

    9.2 What do I need to configure on the web server? What to do if a third party server is not configured properly?

    9.3 What is the relationship and difference between Silverlight and ASP.NET? When should I use either?

    10. CLR:

    10.1 What do I do when my Silverlight application seems to leak memory?

    10.2 What are the restrictions on mini CLR?

    11. Miscellaneous:

    11.1 What should I remember regarding routed events?

    11.2 What offline capabilities does Silverlight support?

    11.3 Does Silverlight support web camera and printing?

     


     

    1. General: [top]

     

    1.1 What is the purpose of this FAQ? [top]

    This FAQ answers common questions that our customers encounter when developing with Silverlight. Most of the questions are hot popular topics we found on this forum. The general target audiences are developers who have intermediate level knowledge of Silverlight. This FAQ is written in the period of Silverlight 2. Since Silverlight is backward compatible the information in this FAQ still applies for future versions of Silverlight. If you find any breaking changes, please do inform us (fbmsdn@microsoft.com).

    If you're a designer who want to work with Silverlight, you can find a lot of resources on the Expression web site: http://expression.microsoft.com. In particular, there're a lot of video tutorials on the learning page. If you have questions, feel free to post them on the Expression Forum.

    If you’ve just started working with Silverlight, please refer to “1.2 What is Silverlight and how do I get started with Silverlight?” It will provide you with resources to help you get started. We do not intend to repeat information provided by the MSDN documents.

    1.2 What is Silverlight and how do I get started with Silverlight? [top]

    Microsoft Silverlight powers rich application experiences and delivers high quality, interactive video across the Web and mobile devices through the most powerful runtime available on the Web.

    Microsoft Silverlight extends and amplifies your existing development skills, empowering you to build new types of applications for the Web regardless of target platform or browser.

    In particular, the RIA Development features include:

    • A compatible subset of the .NET Framework Support with a Rich Base Class Library
    • Powerful Built-in Controls
    • Advanced Skinning and Templating Support
    • Comprehensive Networking Support
    • Expanded .NET Framework Language Support
    • Advanced content protection features, now including Silverlight DRM, Powered by PlayReady
    • Improved Server Scalability and Expanded Advertiser Support
    • Deep Zoom Technology

    To start creating applications with Silverlight, please visit http://silverlight.net/GetStarted/ to download the essential components. The Learn page: http://silverlight.net/Learn/, provides you with useful resources to help you get started.


     

    2. XAML: [top]

     

    2.1 What is namescope? [top]

    In Silverlight, a XAML namescope stores relationships between the XAML-defined names of objects and their instance equivalents. Please refer to: 

    http://msdn.microsoft.com/en-us/library/cc189026(VS.95).aspx for the complete document of namescope.

    Remember the following when working with namescope:

    • When you create a new object with XamlReader.Load, a new namescope will be created.

    A common problem our customers encounter is trying to use a Storyboard to animate a dynamically created object.

    Imagine you have the following markup in your UserControl:

    <UserControl.Resources>

        <Storyboard x:Name="sb">

                       <DoubleAnimation Storyboard.TargetName="btn" Storyboard.TargetProperty="Width" From="0" To="200"/>

             </Storyboard>

    </UserControl.Resources>

     

    In code behind, you create a Button named btn with XamlReader.Load:

    string xaml = @"<Button                                  xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""                                     xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""

                                         x:Name=""btn""/>";

    Button btn = (Button)XamlReader.Load(xaml);

    this.LayoutRoot.Children.Add(btn);

    this.sb.Begin();

     

    This will cause an exception indicating the TargetName of the Storyboard (btn) cannot be found. In this case, the Storyboard is in namescope1. The Button created by XamlReader.Load is in namescope2. The Storyboard can’t find anything named btn in namescope1, so the exception is thrown.

    One way to fix this problem is to remove the TargetName in the DoubleAnimation’s markup, and set the target of the Storyboard dynamically in code after the Button is created. This can bypass the namescope issue.

    Storyboard.SetTarget(this.sb.Children[0], btn);

    A better solution to create a reusable Storyboard is to put the Storyboard in a UserControl. See “5.2 How do I create a Storyboard and apply it to multiple elements?” for more information.

    • A Template (ControlTemplate and DataTemplate) defines its own namescope.

    A common problem our customers encounter is: In code behind, they can’t find an element defined in a Template. For example:

    <Button x:Name="btn" >

             <Button.Template>

                       <ControlTemplate TargetType="Button">

                                <Rectangle x:Name="rect" Fill="Aqua"/>

                       </ControlTemplate>

             </Button.Template>

    </Button>

    Here you won’t find the Rectangle named rect directly in code behind with this.rect. Even

    Rectangle rect = (Rectangle)this.btn.FindName("rect");

    -won’t work.

    To find the Rectangle, you can handle the Loaded event of rect. In code behind, you’ll be able to get the reference to the Rectangle via the sender parameter:

    private Rectangle rect;

    private void rect_Loaded(object sender, RoutedEventArgs e)

    {

             this.rect = (Rectangle)sender;

    }

     

     

    2.2 What should I remember when using XamlReader to create objects dynamically? [top]

    You can find the documents of XamlReader.Load at: 

    http://msdn.microsoft.com/en-us/library/cc190359(VS.95).aspx.

    • As indicated in “2.1 What is namescope?”, you must be careful with the namescope issue.

    • The root element in the XAML snip must have the default xml namespace: xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation.

    • If you need to define x:Name, the root element in the XAML snip must have the xml namespace: xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml.

    • XamlReader.Load doesn’t support defining event handlers in markup. To add event handlers, use FindName to find the desired element and add event handlers in code.

    • Using XamlReader is not recommended.  .Load simply for creating objects dynamically in code. Use it only for serialize/deserialize purposes. To create objects dynamically, call their constructors. To create reusable components, write UserControls.


     

    3. Web Service: [top]

     

    3.1 What is the cross domain/scheme/zone policy? How do I configure it? [top]

    • Cross domain: A domain is represented by a single domain name. For example, www.company1.com represents a domain, while www.company2.com represents another domain. If a Silverlight application is hosted under www.company1.com, while a resource, such as a web service, is hosted under www.company2.com, this is considered a cross domain scenario. Likewise, localhost:80 and localhost:81, or www.company1.com and subdomain.company1.com are also considered to be different domains.

    • Cross scheme: There are three types of schemes:

    1. http

    2. https

    3. file

    If a Silverlight application is copied to local disk, and you double click the hosting html page to launch it, it will be hosted in the file scheme. If a resource is hosted under the http or https scheme, this is considered a cross scheme scenario.

    • Cross Zone: This is IE specific. Under “Internet Options”, click the Security tab, and you’ll find 4 security zones.

    Do we support those cross*** scenarios? For more information you can refer to:

    http://msdn.microsoft.com/en-us/library/cc189008(VS.95).aspx for a detailed table.

    In this table, please pay attention to the line:

    Requires a security policy file.

    This means a valid security policy file must be present at the root of the web server. For example, if the domain is www.company1.com, a valid security policy file is: http://www.company1.com/clientaccesspolicy.xml, or http://www.company1.com/crossdomain.xml. If the web server is IIS with default settings, you can put the policy file under C:\inetpub\wwwroot. If you’re creating a self-hosted WCF service, please refer to “3.2 How do I provide a cross domain policy file for a self-host WCF service?” for a solution.

    3.2 How do I provide a cross domain policy file for a self-host WCF service? [top]

    While it’s easy to provide a cross domain policy file for IIS hosted web services, for self-host WCF services, you have to serve the file programmatically.

    Imagine you have the following simple service hosting code (the actual service is not important):

    ServiceHost host = new ServiceHost(typeof(Service1));

    host.Open();

    Console.Read();

    host.Close();

    You have specified the base address to be:

    <add baseAddress="http://localhost:8731/Service1/" />

    When trying to call the service from a Silverlight application, you’ll get a cross domain issue since you can’t host the Silverlight application in the same console application. Putting a cross domain policy file in the same directory with the console exe won’t help since it’s not read. You need to programmatically serve the file.

    We can start by creating another WCF Service. We can name it CrossDomainService. Here’s the configuration:

    <system.serviceModel>

             <behaviors>

                       <serviceBehaviors>

                                <behavior name="ConsoleHostWcf.Service1Behavior">

                                         <serviceMetadata httpGetEnabled="true" />

                                         <serviceDebug includeExceptionDetailInFaults="false" />

                                </behavior>

                                <behavior name="ConsoleHostWcf.CrossDomainServiceBehavior">

                                         <serviceMetadata httpGetEnabled="true" />

                                         <serviceDebug includeExceptionDetailInFaults="false" />

                                </behavior>

                       </serviceBehaviors>

                       <endpointBehaviors>

                                <behavior name="webBehavior">

                                         <webHttp/>

                                </behavior>

                       </endpointBehaviors>

             </behaviors>

    <services>

                       <service behaviorConfiguration="ConsoleHostWcf.Service1Behavior"

                                                   name="ConsoleHostWcf.Service1">

    <endpoint address="" binding="basicHttpBinding" contract="ConsoleHostWcf.IService1">

                                         <identity>

                                                   <dns value="localhost" />

                                         </identity>

                                </endpoint>

                                <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />

                 <host>

                                         <baseAddresses>

                                                   <add baseAddress="http://localhost:8731/Service1/" />

                                         </baseAddresses>

                                </host>

                       </service>

                       <service behaviorConfiguration="ConsoleHostWcf.CrossDomainServiceBehavior"

                                                   name="ConsoleHostWcf.CrossDomainService">

                                <endpoint address="" binding="webHttpBinding" behaviorConfiguration="webBehavior"

                                            contract="ConsoleHostWcf.ICrossDomainService">

                                </endpoint>

                                <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />

                                <host>

                                         <baseAddresses>

                                                   <add baseAddress="http://localhost:8731/" />

                                         </baseAddresses>

                                </host>

                       </service>

             </services>

    </system.serviceModel>

     

    Some notes:

    • This new service must use WebHttpBinding. You need to reference System.ServiceModel.Web.dll.

    • You need an EndpointBehavior where you specify webHttp.

    • The base address for the REST service is modified to http://localhost:8731, because the cross domain policy file must be served from there.

    Now go on with the service interface. Other than the OperationContract attribute, you’ll need an UriTemplate. Here we specify the template to be “clientaccesspolicy.xml”. Combined with the base address specified in the above configuration, you’ll be able to get the service with the URI: http://localhost:8731/clientaccesspolicy.xml, and that is exactly what we want. Also, note if the method returns a sting.  It will be wrapped by an extra xml element. This is the default behavior of DataContractSerializer. To work around it, you can return an untyped Message.

    [OperationContract]

    [WebGet(UriTemplate = "clientaccesspolicy.xml")]

    Message GetPolicyFile();

     

    Here is the service implementation. It merely reads the file and returns its content. A MessageBuffer is needed. If you simply return the original message, an exception will be thrown because the underlying FileStream and XmlReader have already been disposed (since we put them in using blocks). It is also not a good idea to leave unmanaged resources opened, so don’t simply remove the using blocks.

    public Message GetPolicyFile()

    {

             using (FileStream stream = File.Open("clientaccesspolicy.xml", FileMode.Open))

             {

                       using (XmlReader xmlReader = XmlReader.Create(stream))

                       {

                                Message m = Message.CreateMessage(MessageVersion.None, "", xmlReader);

                                using (MessageBuffer buffer = m.CreateBufferedCopy(1000))

                                {

                                         return buffer.CreateMessage();

                                }

                       }

             }

    }

     

    Finally, return to the Console application and create another service host:

    static void Main(string[] args)

    {

             ServiceHost host = new ServiceHost(typeof(Service1));

             ServiceHost host2 = new ServiceHost(typeof(CrossDomainService));

             host.Open();

             host2.Open();

             Console.Read();

             host.Close();

             host2.Close();

    }

     

    To verify if the service works, open your browser and type http://localhost:8731/clientaccesspolicy.xml. You should be able to see the content of the cross domain policy file. Now you’ll be able to call the services from a Silverlight application.

    3.3 How do I call a web service without a proxy? [top]

    Several customers encounter scenarios in which they don’t want to use the “Add Service Reference” feature. In those cases, you have to understand the contract provided by the service, create local DataContracts, and then send messages manually. To do this, you’ll need to reference the service’s WSDL document to determine how to create the local DataContracts and send the messages.

    Imagine we have the following service:

    [ServiceContract]

             public interface IService1

             {

                       [OperationContract]

                       string DoWork(string name);

             }

    As the developer of the service, you known well about the contract. But the consumers of your service only have knowledge of the WSDL document. Part of the WSDL document looks like this:

    <wsdl:message name="IService1_DoWork_InputMessage">

             <wsdl:part name="parameters" element="tns:DoWork"/>

    </wsdl:message>

     

    <wsdl:message name="IService1_DoWork_OutputMessage">

             <wsdl:part name="parameters" element="tns:DoWorkResponse"/>

    </wsdl:message>

     

    <wsdl:operation name="DoWork">

    <wsdl:input wsaw:Action="http://tempuri.org/IService1/DoWork"     message="tns:IService1_DoWork_InputMessage"/>

    <wsdl:output wsaw:Action=http://tempuri.org/IService1/DoWorkResponse message="tns:IService1_DoWork_OutputMessage"/>

    </wsdl:operation>

     

    and the xml schema is:

    <xs:schema elementFormDefault="qualified" targetNamespace="http://tempuri.org/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://tempuri.org/">

             <xs:element name="DoWork">

                       <xs:complexType>

                                <xs:sequence>

                                         <xs:element minOccurs="0" name="name" nillable="true" type="xs:string"/>

                                </xs:sequence>

                       </xs:complexType>

             </xs:element>

             <xs:element name="DoWorkResponse">

                       <xs:complexType>

                                <xs:sequence>

    <xs:element minOccurs="0" name="DoWorkResult" nillable="true" type="xs:string"/>

                                </xs:sequence>

                       </xs:complexType>

             </xs:element>

    </xs:schema>

    This is the information needed to work with the service without a proxy. Now I'll show you two ways to work with the service. One way is to create a client channel (which is similar to using a proxy), and the other is to send messages directly. I will first list the code and then explain it.

     

        [ServiceContract]

        public interface IService1

        {

           [OperationContract(AsyncPattern = true)]

           IAsyncResult BeginDoWork(string name, AsyncCallback callback, object asyncState);

     

           string EndDoWork(System.IAsyncResult result);

        }

     

        public interface IService1Channel : IService1, IClientChannel { }

     

               ChannelFactory<IService1Channel> factory = new ChannelFactory<IService1Channel>(new BasicHttpBinding(), new EndpointAddress("http://localhost:60486/Service1.svc/"));

               factory.BeginOpen(openResult =>

               {

                  factory.EndOpen(openResult);

                  IService1Channel channel = factory.CreateChannel();

                  channel.BeginOpen(channelOpenResult =>

                  {

                      channel.BeginDoWork("abc", new AsyncCallback((operationResult) =>

                      {

                         string result = channel.EndDoWork(operationResult);

                         this.Dispatcher.BeginInvoke(new Action(() =>

                         {

                             textBlock1.Text = result;

                         }));

                      }), null);

                  }, null);

               }, null);

     

     

    • Create an operation contract based on the WSDL document using the asynchronous pattern. In the above WSDL, we have an operation named DoWork.

    • Create a data contract based on the WSDL document. In the above WSDL, while the input and output schema of our DoWork operation are both complex types, since they only contains a single element of type string, we can use a string for our data contract. For more complex schemas, you will need to create a class corresponding to the schema.

    • Create a channel interface which derives from IClientChannel and the operation contract you created before.

    • Create a ChannelFactory with BasicHttpBinding and the proper EndpointAddress.

    • Open the ChannelFactory and create the channel.

    • Open the channel and work with the operation.

    • Close the channel and the ChannelFactory (omitted in the previous sample).

     

    The above solution may look similar to working with the system generated proxy. But it doesn't contain code such as the ***CompletedEventArgs. So it is a bit cleaner than the generated proxy. If you want even more control over the message being exchanged between the client and the service, or if you want to completely get rid of the operation contract, you can build a IRequestChannel instead of a client channel:

    BasicHttpBinding binding = new BasicHttpBinding();

    EndpointAddress address = new EndpointAddress("http://localhost:8731/Service1.svc");

    var factory = binding.BuildChannelFactory<IRequestChannel>();

    factory.BeginOpen(openResult =>

    {

             factory.EndOpen(openResult);

             IRequestChannel channel = factory.CreateChannel(address);

             channel.BeginOpen(channelOpenResult =>

             {

    Message requestmessage = Message.CreateMessage(MessageVersion.Soap11, "http://tempuri.org/IService1/DoWork", new DoWork() { Name = "abc" });

                       channel.BeginRequest(requestmessage, requestResult =>

                       {

                                Message responseMessage = channel.EndRequest(requestResult);

                                DoWorkResponse response = responseMessage.GetBody<DoWorkResponse>();

                                string result = response.DoWorkResult;

    channel.BeginClose(channelCloseResult =>

                                {

                                         channel.EndClose(channelCloseResult);

                                         factory.BeginClose(closeResult =>

                                         {

                                                   factory.EndClose(closeResult);

                                         }, null);

                                }, null);

                       }, null);

             }, null);

    }, null);

     

    [DataContract(Namespace = "http://tempuri.org/")]

    public class DoWork

    {

             [DataMember]

             public string Name { get; set; }

    }

     

    [DataContract(Namespace = "http://tempuri.org/")]

    public class DoWorkResponse

    {

             [DataMember]

             public string DoWorkResult { get; set; }

    }

     

    Below are the necessary steps:

    • Create a BasicHttpBinding.

    • Build a ChannelFactory.

    • Open the ChannelFactory and create the IRequestChannel.

    • Open the channel and send a message.

    • Based on the xml schema found in WSDL, create a corresponding DoWork class. Make sure the namespace is correct. An instance of this class is used as the message body.

    • After a response message is returned, create another class DoWorkResponse as described in WSDL.

    • Close the channel and the ChannelFactory.

    Note:  While you can open/close the factory and channel synchronously, you must send the message asynchronously. To avoid confusion, you can do everything asynchronously.

     

    3.4 What are the restrictions of web service accessing in Silverlight 2? [top]

    For SOAP:

    Silverlight 2 supports most features of SOAP 1.1 and WS-I Basic Profile 1.0, but it doesn’t support SOAP 1.2 or above. Features such as WS-Security and WS-Addressing are not supported. If you’re working with WCF, please use BasicHttpBinding and mark types as DataContract/Member to ensure Silverlight compatibility. If you’re working with ASMX/Java/PHP, etc, you’ll need to make sure your service compromises SOAP 1.1 and WS-I Basic Profile 1.0. For example, do not use DataSet.

    Silverlight 3 adds support for SOAP1.2 and WS-Addressing, as well as the Binary XML format (CustomBinding with the binaryMessageEncoding and http/https Transport binding elements). Additionally, a small subset of WS-Security is supported: Username/Password tokens (BasicHttpBinding in TransportWithMessageCredentials mode)

    For REST:

    Silverlight 2 supports the GET and POST verb.  Other verbs are not supported. Additionally, certain http features are not available – for example, certain  http headers such as Authentication are not supported.

    XML message bodies are supported using the XmlSerializer or using LINQ-to-XML (System.Xml.Linq.XElement class). To use the XmlSerializer, you may generate types automatically from sample XML by using the “Paste XML as Types” add-in to Visual Studio available in the WCF REST Starter Kit.

    JSON message bodies are supported using the DataContractJsonSerializer or using LINQ-to-JSON (System.Json.JsonValue class). RSS and Atom message bodies can be parsed as plain XML, or can be parsed using the System.ServiceModel.Syndication types.


    4. Graphics: [top]

    4.1 What graphic related features are supported in Silverlight 2? [top]

    Computer graphic is a complex subject. Silverlight 2 basically supports the following features:

    • Draw 2D vector graphics such as rectangle, ellipse, and path with fill and/or stroke.

    • Brushes: SolidColorBrush, Linear/RadialGradientBrush, ImageBrush, VideoBrush.

    • Opacity mask.

    • Shape (supports mouse/keyboard events) and Geometry (lightweight).

    • EvenOdd and Nonzero path fill rule.

    • Affine transforms.

    • Render bitmap images encoded with jpg and png.

    • Ink and stylus devices.

    • Download and view large bitmap images efficiently with Deep Zoom.

    The following features are not supported in V2:

    • 3D.

    • PathGradientBrush, DrawingBrush, VisualBrush.

    • StreamGeomerty.

    • Compound path operations, such as union and intersect.

    • Compound paths.

    • Non-affine transforms, such as perspective transform.

    • Render bitmap images encoded with gif, bmp, or other formats.

    • Pixel level editing of bitmap images.

    • Pixel shader effects.

    • Create a screen shot with RenderTargetBitmap.

    Silverlight 3 will support more features such as perspective transform and pixel shader.

    You can find common graphic related tasks under http://msdn.microsoft.com/en-us/library/cc189060(VS.95).aspx. If you need to perform more advanced tasks, first you will have to understand some basic math concepts, such as vector and matrix, and then find an algorithm (or create your own) to perform that task, and then combine the basic tasks to get the result. This FAQ is not intended to describe algorithms in computer graphics since they’re not Silverlight specific.

    4.2 How do I create 3D effect? [top]

    Silverlight 2 doesn’t support 3D, and Silverlight 3 will only support perspective transform (rotate a 2D surface in a 3D world). However, you can find several 3D libraries, such as Kit3D, which allows you to create 3D effects similar to WPF. How to use those libraries is out of this FAQ’s scope. You can refer to the WPF documents. 

    Sometimes you may only need to simulate 3D effects, without requiring models, lights, and textures. In such cases, you can wait for Silverlight 3, which supports perspective transform. You can also achieve some effects in Silverlight 2. http://silverlight.net/forums/p/24136/86878.aspx shows a sample on how to simulate the Mojave Experiment.


     

    5. Animation: [top]

     

    5.1 How do I create animation without Storyboard? [top]

    As a Silverlight developer, you probably know how to create animation with Storyboards.  Sometimes you may find it is not enough. For example, when developing a game, it’s often required to perform actions such as move an object to a particular location based on a timer. There are two solutions to animate a scene without a Storyboard. One is to use a DispatcherTimer, and the other is to handle the CompositionTarget.Rendering event.

    • DispatcherTimer

    DispatcherTimer is a thread safe timer. Each callback is performed on the UI thread.  This means you can use it without worrying about thread related issues. This is different from System.Threading.Timer, which fires the callback on a different thread. Below is a sample:

    <Ellipse x:Name="ell" Fill="Blue" Width="100" Height="100" Canvas.Left="300" Canvas.Top="300">

             <Ellipse.RenderTransform>

                       <TranslateTransform x:Name="tran"/>

             </Ellipse.RenderTransform>

    </Ellipse>

     

    private DispatcherTimer timer = new DispatcherTimer();

    private Random random = new Random();

    private void LayoutRoot_Loaded(object sender, RoutedEventArgs e)

    {

             timer.Interval = TimeSpan.FromSeconds(1);

             timer.Tick += new EventHandler(timer_Tick);

             timer.Start();

    }

     

    void timer_Tick(object sender, EventArgs e)

    {

             this.tran.X += random.Next(-10, 10);

             this.tran.Y += random.Next(-10, 10);

    }

     

    Please note in the timer’s callback, we can directly update UI without using Dispatcher.BeginInvoke.

    Generally, if you want to do something based on the timeline, but you can’t predict what values are required, and thus cannot specify the From and To properties in a Storyboard, you will use a DispatcherTimer .

    • CompositionTarget.Rendering

    The CompositionTarget.Rendering event is fired each time a frame is rendered. This gives you a chance to modify the final rendered frame. Here’s a sample:

    CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);

     

    void CompositionTarget_Rendering(object sender, EventArgs e)

    {

             this.tran.X += random.Next(-10, 10);

             this.tran.Y += random.Next(-10, 10);

    }

    Based on your machine’s speed, the speed of the animation will be quite different. Do not rely on this event when you need a timeline based animation. You normally handle this event when you need to make sure the animation won’t lose a single frame.

    5.2 How do I create a Storyboard and apply it to multiple elements? [top]

    Quite a few people try to reuse a Storyboard on multiple elements, but encounter some problems. For example, you have a Storyboard:

    <Storyboard x:Name="sb">

    <ColorAnimation From="Red" To="Blue" Storyboard.TargetProperty="(Ellipse.Fill).(SolidColorBrush.Color)" Duration="00:00:05"/>

    </Storyboard>

     

    In code behind, you want to create 5 Ellipases and animate them, so you get:

    for (int i = 0; i < 5; i++)

    {

             Ellipse ellipse = new Ellipse();

             ellipse.Width = 100;

             ellipse.Height = 100;

             ellipse.Fill = new SolidColorBrush(Colors.Red);

             ellipse.SetValue(Canvas.LeftProperty, (double)random.Next(0, 600));

             ellipse.SetValue(Canvas.TopProperty, (double)random.Next(0, 600));

             this.LayoutRoot.Children.Add(ellipse);

             Storyboard.SetTarget(sb.Children[0], ellipse);

             this.sb.Begin();

    }

     

    If you run the above code, an exception will be thrown, and the application will stop working.  This indicates the Storyboard must stop before its target can be modified. This is by design, and it is necessary because even if you can call SetTarget to make the Storyboard animate the second Ellipse, the first Ellipse’s animation will be disrupted. After all, there’s only a single Storyboard in this case.

    A better solution is to create a UserControl to encapsulate the Ellipse and the Storyboard.

    <UserControl x:Class="ReuseAnimation.AnimatedEllipse"

                            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

                            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

                               Loaded="UserControl_Loaded">

             <UserControl.Resources>

                       <Storyboard x:Name="sb">

                                <ColorAnimation From="Red" To="Blue" Storyboard.TargetName="ellipse"

    Storyboard.TargetProperty="(Ellipse.Fill).(SolidColorBrush.Color)"

    Duration="00:00:05"/>

                       </Storyboard>

             </UserControl.Resources>

     

             <Ellipse x:Name="ellipse" Fill="Red">

        </Ellipse>

    </UserControl>

     

    private void UserControl_Loaded(object sender, RoutedEventArgs e)

    {

             sb.Begin();

    }

     

    Now in the main page, simply add five instances of this UserControl:

    for (int i = 0; i < 5; i++)

    {

             AnimatedEllipse ae = new AnimatedEllipse();

             ae.Width = 100;

             ae.Height = 100;

             ae.SetValue(Canvas.LeftProperty, (double)random.Next(0, 600));

             ae.SetValue(Canvas.TopProperty, (double)random.Next(0, 600));

             this.LayoutRoot.Children.Add(ae);

    }

     

    This approach creates a clean code and also makes the animation reusable as long as you only want to animate Ellipses.

    If you need to animate different types of objects, such as an Ellipse and a Rectangle, you can modify the UserControl so that it accepts a parameter, and constructs the desired object dynamically. Alternatively, you can create a new Storyboard in code for each object to animate, so you don’t need a UserControl.

     

    5.3 What’s the difference between animation in Flash and Silverlight? [top]

    A common question from designers is “What’s the difference between animation in Flash and Silverlight, and how do I migrate a Flash animation to Silverlight?” Here are the major differences:

    • In Silverlight, there is no main timeline. You need to create a timeline manually and start the animation in code. This is the most significant difference. Future versions of Expression Blend will improve on this area so that designers will not need to worry about the code.

    • In Silverlight, you can create more than one timeline. This is similar to Flex, but different from Flash, where you may have to create more scenes to add more timelines.

    • In Expression Blend, motion tweens are added automatically when you add a new key frame.

    • In Silverlight, you cannot dynamically add and remove elements on a scene. You can add everything to the stage at the beginning, and make elements you don’t want to show initially show as invisible by setting Visibility to Collapsed or Opacity to 0. In the animation, when you want to display the element, you need to modify the Visibility and/or Opacity property.

    • The UserControl concept in Silverlight is similar to the Scene concept in Flash, but you don’t create a UserControl solely for a new timeline. You create UserControls when you want to divide your elements logically or when you need to reuse a piece of design artwork.

    • There’s no layer concept in Silverlight, but you can group objects into containers such as Canvas and Grid.

    • Some features are not supported in Silverlight, such as motion path.


     

    6. Multimedia: [top]

     

    6.1 What media types are supported in Silverlight 2? [top]

    You can find a list of supported media formats on http://msdn.microsoft.com/en-us/library/cc189080(VS.95).aspx. Essentially, Silverlight 2 supports wmv, wma, and mp3. It is recommended that you use Expression Encoder to encode your media before playing it in Silverlight.

    Silverlight 3 will support additional media formats, such as H264 (mp4) and AAC. Raw audios and videos will also be supported.

    6.2 How do I modify the media player generated by Expression Encoder 2? [top]

    After you install Expression Encoder 2 SP1, you will be able to create Silverlight 2 templates as job output. However, the generated content is a xap file, a complete Silverlight application without source code, which will be directly embedded in an html page. How can you modify the player in your own application? Here are the necessary steps:

    To use the player:

    • Rename the xap file to zip and extract its content. After you unzip the file, you’ll get a few dll files. Each dll file is called an assembly.

    • In your own project, add references to all those assemblies.

    • Add a namespace mapping:

    xmlns:player="clr-namespace:ExpressionMediaPlayer;assembly=MediaPlayer"

     

    • Create the MediaPlayer Control in XAML:

    <player:MediaPlayer x:Name="player">

             <player:MediaPlayer.Playlist>

       <player:PlaylistItem Title="My Title" MediaUrl="myvedio.wmv"/>

    </player:MediaPlayer.Playlist>

    </player:MediaPlayer>

     

    This code will allow you to get a fully functional media player.

    To modify the template of the player, simply use Expression Blend to modify the ControlTemplate, as you do with normal Controls.

    6.3 How do I open and play a local media file? [top]

    While Silverlight2 was designed for online scenarios, from time to time, you may want to let the user play a local media file. To do so, you can use the OpenFileDialog.

    private FileStream fs;

     

    OpenFileDialog ofd = new OpenFileDialog();

    if (ofd.ShowDialog().Value)

    {

             this.fs = ofd.File.OpenRead();

             //me is a MediaElement.

             this.me.SetSource(fs);

             this.me.Play();

    }

     

     

    Don’t forget to close the FileStream when you no longer need to play the media.

    At this point, you can perform further actions such as uploading the file stream to a web server.


     

    7. Data: [top]

     

    7.1 What data binding features of WPF are not yet supported in Silverlight? Is there a workaround? [top]

    The following data binding features are not supported in Silverlight yet:

    • Element to element binding

    Workaround: Wait for Silverlight 3 which will support this feature.

    • UpdateSourceTrigger

    Workaround: Wait for Silverlight 3 which will support this feature.

    • CollectionViewSource

    Workaround: You’ll have to perform the sorting, filtering, etc operations on the data source. If you need to protect the original data source, you can consider creating a copy of it.

    • Data validation

    Workaround: Wait for Silverlight 3 which will support this feature.

    • DataTemplateSelector

    Workaround:

    Imagine you have the following ListBox:

    <ListBox x:Name="lb">

             <ListBox.ItemTemplate>

                       <DataTemplate>

                                <StackPanel>

                                         <TextBlock Text="{Binding Name}"/>

                                         <TextBlock Text="{Binding Age}"/>

                                </StackPanel>

                       </DataTemplate>

             </ListBox.ItemTemplate>

    </ListBox>

     

     

    You want to display a different foreground based on the value of Age. In this case, you can bind the TextBlock’s Foreground to the Age property with a converter. However, if you need to display a lot of different content based on the value of Age, this approach will introduce a lot of code. In WPF, you can use a DataTemplateSelector to avoid a lot of code. In Silverlight, while no DataTemplateSelector exists, you can use a similar solution:

    Create two DataTemplates:

    <DataTemplate x:Key="dt1">

             <StackPanel>

                       <TextBlock Foreground="Red" Text="{Binding Name}"/>

                       <TextBlock Foreground="Red" Text="{Binding Age}"/>

             </StackPanel>

    </DataTemplate>

                      

    <DataTemplate x:Key="dt2">

             <StackPanel>

                       <TextBlock Foreground="Blue" Text="{Binding Name}"/>

                       <TextBlock Foreground="Blue" Text="{Binding Age}"/>

             </StackPanel>

    </DataTemplate>

     

    Modify the ListBox to:

    <ListBox x:Name="lb">

             <ListBox.ItemTemplate>

                       <DataTemplate>

                                <ContentControl Content="{Binding}" Loaded="ContentControl_Loaded"/>

                       </DataTemplate>

             </ListBox.ItemTemplate>

    </ListBox>

     

    Note Content=”{Binding}” cannot be omitted, or the DataContext won’t pass down to the ContentControl’s ContentTemplate.

    Now you can assign different ContentTemplates to the ContentControl according to the data source:

    private void ContentControl_Loaded(object sender, RoutedEventArgs e)

    {

             ContentControl cc = (ContentControl)sender;

             Data d = (Data)cc.DataContext;

             if (d.Age > 20)

             {

                       cc.ContentTemplate = (DataTemplate)this.Resources["dt1"];

             }

             else

             {

                       cc.ContentTemplate = (DataTemplate)this.Resources["dt2"];

             }

    }

     

    • No direct support for binding to xml.

    Workaround: You have to use LINQ to XML to create a CLR object data source.

    • Cannot bind to a method.

    Workaround: Not available.

    • Binding source can only be FrameworkElement, not arbitrary DependencyObject.

    Workaround: Not available.

     

    7.2 How do I bind to flexible (untyped) data sources? [top]

    Silverlight 2’s data binding engine was designed with strong type in mind. It requires you to have a pre-defined object model. This is sufficient for most scenarios, however, there are also several scenarios where you need a more flexible data source because you don’t yet know the structure of data source beforehand. This is particularly useful when using it together with a DataGrid since DataGrid supports auto generate columns.

    For example, in SharePoint, a user can define a data source by adding custom columns to a GridView. SharePoint stores the user’s configuration in a metadata rather than create database tables based on the columns. At runtime, it dynamically generates GridView columns based on the configuration.

    In Silverlight, you can use a similar solution. This solution will involve some reflection and emitting code. Generally, emitting code is difficult to write unless you have a strong understanding of MSIL. A tip here is to write a simple application, such as this:

     

    public class Class1

    {

             private int _Age;

             public int Age

             {

                       get { return _Age; }

                       set { _Age = value; }

             }                

    }

    Use Reflector to view the IL for the getter and setter, and you’ll see:

    L_0000: nop 
    L_0001: ldarg.0 
    L_0002: ldfld int32 SilverlightClassLibrary1.Class1::_Age
    L_0007: stloc.0 
    L_0008: br.s L_000a
    L_000a: ldloc.0 
    L_000b: ret 

    The essential code here is:

    ldarg.0

    ldfld int32 SilverlightClassLibrary1.Class1::_Age

    ret

    That is: Load the method’s address to call stack as the first parameter, load the field named _Age, and return its value.

    Similarly, the IL for a setter is:

    ldarg.0

    ldarg.1

    stfld int32 SilverlightClassLibrary1.Class1::_Age

    ret

    Load the method’s address to the call stack as the first parameter, load the actual parameter passed to the setter as the second parameter to the call stack, set the field _Age’s value, and return.

    For more information, please refer to the CLR document.

    With the knowledge of emitting in mind, we can go on to define our metadata. We’ll need a Dictionary to store the column name with its type. Each metadata will contain a list of rows. Each row has a Dictionary to map its values to the columns. We get the following data structure:

    public class Metadata

    {

             public Dictionary<string, Type> Columns { get; set; }

             public List<MetadataRow> Rows { get; set; }

    }

     

    public class MetadataRow

    {

             public Dictionary<string, object> ColumnValues { get; set; }

    }

    Suppose we have the metadata in our hand, our next job is to create a type dynamically based on the information provided in the metadata. We’ll use emitting to generate the type. First create a type named DataSource. Then add properties according to columns defined in the metadata. For more information on how to create types dynamically using emitting, please refer to http://msdn.microsoft.com/en-us/library/4xxf1410(VS.95).aspx.

    AppDomain myDomain = AppDomain.CurrentDomain;

    AssemblyName myAsmName = new AssemblyName("MyAssembly");

    AssemblyBuilder myAssembly = myDomain.DefineDynamicAssembly(myAsmName,

    AssemblyBuilderAccess.Run);

    ModuleBuilder myModule = myAssembly.DefineDynamicModule(myAsmName.Name);

    TypeBuilder myType = myModule.DefineType("DataSource", TypeAttributes.Public);

    foreach (string columnName in metadata.Columns.Keys)

    {

             Type properyType = metadata.Columns[columnName];

             FieldBuilder exField = myType.DefineField("_" + columnName, properyType, FieldAttributes.Private);

             PropertyBuilder exProperty = myType.DefineProperty(columnName, PropertyAttributes.None,

    properyType, Type.EmptyTypes);

             //Get

             MethodBuilder exGetMethod = myType.DefineMethod("get_" + columnName,

    MethodAttributes.Public, properyType, Type.EmptyTypes);

             ILGenerator getIlgen = exGetMethod.GetILGenerator();

    //IL for a simple getter:

             //ldarg.0

             //ldfld int32 SilverlightClassLibrary1.Class1::_Age

             //ret

             getIlgen.Emit(OpCodes.Ldarg_0);

             getIlgen.Emit(OpCodes.Ldfld, exField);

             getIlgen.Emit(OpCodes.Ret);

             exProperty.SetGetMethod(exGetMethod);

             //Set

             MethodBuilder exSetMethod = myType.DefineMethod("set_" + columnName,

    MethodAttributes.Public, null, new Type[] { properyType });

             ILGenerator setIlgen = exSetMethod.GetILGenerator();

             //IL for a simple setter:

             //ldarg.0

             //ldarg.1

             //stfld int32 SilverlightClassLibrary1.Class1::_Age

             //ret

             setIlgen.Emit(OpCodes.Ldarg_0);

             setIlgen.Emit(OpCodes.Ldarg_1);

             setIlgen.Emit(OpCodes.Stfld, exField);

             setIlgen.Emit(OpCodes.Ret);

             exProperty.SetSetMethod(exSetMethod);

    }

    Type finished = myType.CreateType();

     

    After the type and properties are created, we now need to create one instance of DataSource for each row, and populate the values by setting properties, and finally set the DataGrid’s ItemsSource. This task is much easier since only reflection is needed:

    ObservableCollection<object> source = new ObservableCollection<object>();

    foreach (MetadataRow row in metadata.Rows)

    {

             object item = Activator.CreateInstance(finished);

             foreach (string columnName in metadata.Columns.Keys)

             {

                       MethodInfo method = finished.GetMethod("set_" + columnName);

                       method.Invoke(item, new object[] { row.ColumnValues[columnName] });

             }

             source.Add(item);

    }

    this.dg.ItemsSource = source;

     

     

    Now you can test the code above, as an example, we just populate some fake data. In a real scenario, you will probably try to let the users define their own columns, values, serialize the metadata to xml, call a REST service and save it on the server.

    Metadata metadata = new Metadata();

    metadata.Columns = new Dictionary<string, Type>();

    metadata.Columns.Add("Column1", typeof(string));

    metadata.Columns.Add("Column2", typeof(int));

    metadata.Columns.Add("Column3", typeof(bool));

    metadata.Rows = new List<MetadataRow>();

    Dictionary<string, object> row1Values = new Dictionary<string, object>();

    row1Values.Add("Column1", "abc");

    row1Values.Add("Column2", 2);

    row1Values.Add("Column3", true);

    metadata.Rows.Add(new MetadataRow() { ColumnValues = row1Values });

    Dictionary<string, object> row2Values = new Dictionary<string, object>();

    row2Values.Add("Column1", "xyz");

    row2Values.Add("Column2", 20);

    row2Values.Add("Column3", true);

    metadata.Rows.Add(new MetadataRow() { ColumnValues = row2Values });

    Dictionary<string, object> row3Values = new Dictionary<string, object>();

    row3Values.Add("Column1", null);

    row3Values.Add("Column2", 0);

    row3Values.Add("Column3", false);

    metadata.Rows.Add(new MetadataRow() { ColumnValues = row3Values });


     

    8. Socket: [top]

    8.1 What is the socket accessing policy? How do I create a socket policy server? [top]

    A Silverlight 2 application can work as a socket client, with some restrictions:

    • The socket server must listen at port 4502 - 4534. Silverlight can’t communicate with socket servers listening at other ports.

    • A valid socket access policy file must be served on port 943, even if the Silverlight application and the socket server are hosted in the same domain.

    • Only TCP is supported. Protocols such as UDP can’t be used.

    • Only asynchronous operations are supported on the Silverlight client.

    The most important part is to serve a policy file. This is similar to “3.2 How do I provide a cross domain policy file for a self-host WCF service?”, You must serve the file programmatically. The Silverlight 2 documentation contains a sample demonstrating how to create a socket policy server.  You can find the sample at the end of: 

    http://msdn.microsoft.com/en-us/library/cc645032(VS.95).aspx.


     

    9. Html and ASP.NET integration: [top]

     

    9.1 How do I use InitParams? [top]

    You can pass parameters from the hosting html page to the Silverlight application when it starts. This is similar to passing command line parameters in a console application, you do this by using InitParams.

    The syntax of InitParams sometimes confuses people.  Further clarification is offered below:

    • On the html side:

    On the html side, IntiParams is a simple string, all parameters are put in the same string, and separated with commas. Below is how to create InitParams when using the object tag:

     

    <param name="initParams" value="first=abc, second=xyz"/>

     

    Below shows how to create InitParams when using asp:Silverlight server control. Note, in this case, the property is named InitParameters.

    <asp:Silverlight InitParameters="first=abc, second=xyz"/>

     

    • On the Silverlight side:

    On the Silverlight side, you can only get InitParams during the Application_Startup event handler. Of course, once you get the parameters, you’re free to store them as global variables. On the Silverlight site, this property is no longer a string, it’s a dictionary. You can use the following code to get the parameters:

    private void Application_Startup(object sender, StartupEventArgs e)

                       {

                                string first = e.InitParams["first"];

                                string second = e.InitParams["second"];

                                this.RootVisual = new Page();

                       }

     

     

    9.2 What do I need to configure on the web server? What to do if a third party server is not configured properly? [top]

    Silverlight is a client side technology, which has minimum dependency on the server. However, the web server still needs a few configurations in order to serve Silverlight content:

    • The server must be able to serve static files.

    Most servers are capable of this, however we’ve found cases where IIS is not configured properly. If you’re using IIS 7, please make sure “Web Server” => “Common HTTP Features” => “Static Content” is checked.

    • The server needs to configure the MIME Type: Key: “.xap”, Value: “application/x-silverlight-app”.

    If you’re using IIS, this is automatically configured when you install the Silverlight SDK, for other servers, you may need to configure it manually.

    Sometimes when you host your applications on a third party server, you may find the server isn’t configured with the .xap MIME Type (almost all vendors configures their servers to support static content, so that is generally not a problem). In this case, you can simply rename the xap file to zip, as xap is just a zip file., but do not forget to update the references in the hosting html page.

    9.3 What is the relationship and difference between Silverlight and ASP.NET? When should I use either? [top]

    Technically, Silverlight and ASP.NET are completely different.  The major differences are listed below:

    • Silverlight runs completely on the client, while ASP.NET mainly runs on the server, but also has a few parts running on the client.

    • When an event fires, Silverlight handles the event on the client, but in ASP.NET, the browser will make an HTTP POST to the server, and after the server handles the request, it sends a new html page to the client.

    • A Silverlight application sends rendering commands to the Silverlight rendering engine by either write XAML or code, and the Silverlight rendering engine will handle the rendering task. On the other hand, ASP.NET doesn’t have a rendering engine. It generates an html file on the server, sends it to the client, and allows the browser to parse the html file and render the content.

    • Silverlight can’t work with a database directly, instead it consumes data from web services, while ASP.NET has strong support in working with database directly.

    The most important fact to remember is what runs on the client, and what runs on the server, since this will affect almost every part of your system. Silverlight runs on the client, and ASP.NET runs on the server. They can work together and are compatible with each other, but this requires some time and effort.

    Another common question is when to use Silverlight, ASP.NET or both. This depends on different scenarios.  Below are some common approaches:

    • Pure Silverlight.

    One approach is to completely remove ASP.NET, this solution works best if you’re working on a new development. You only need to work on Silverlight, without any worry about integration problems. If you need to communicate with the server, you write web services, such as WCF. It will also help you when you need to port part of or the whole of your system to other hostings or even other platforms, since the client and the server are completely separate.

    • Major ASP.NET plus a Silverlight island.

    This approach is generally used when the Silverlight content and the ASP.NET content have little relationship. For example, an ASP.NET blog engine with a Silverlight media player in a blog post. This approach is very easy to implement, and allows you to reach the broadest audience. For example, if a user hasn’t installed Silverlight, he can still read the blog posts, but he can’t watch the videos.

    • Use ASP.NET AJAX instead of Silverlight

    ASP.NET AJAX is designed to work with ASP.NET. It is mainly an extension to ASP.NET. While AJAX can’t provide you the advance user experience that Silverlight can, for many scenarios, it should be sufficient. This approach also helps if you have strong ASP.NET experience, but  are still quite new to Silverlight.

    Within this approach, there are two branches. One is to mix the client and server code by using UpdatePanel, AJAX Control Toolkit, and etc.  The other method is to take the pure AJAX approach, where you write html and JavaScript instead of using Server Controls, and call web services to communicate with the server. The former branch is easier to implement, especially if you have strong ASP.NET experience, but lack JavaScript knowledge. The latter branch proves to be better in architecture when you want to port the AJAX application to other technologies such as Silverlight.  Especially since you only need to rewrite the client side code, and can keep the web services as they are. The programming model for the later branch is similar to Silverlight. Therefore, this approach is rarely taken if you’re experienced in Silverlight.

    • Mix Silverlight with ASP.NET.

    More often, you may want to port an existing ASP.NET application to Silverlight, but you don’t want to completely rewrite the entire application. This is the most difficult approach since you’re mixing client side and server side technologies.

    Before going with this approach, please consider if the above approaches can solve your problem. Ask yourself the following questions:

          1. Do you really need a rich interactive user experience?   

    This is normally a requirement for consumer oriented applications, but for most business applications, you only need a “good” user experience, which AJAX is sufficient to provide.

          2. Can you add Silverlight islands to your existing ASP.NET application instead of mixing the contents?

    This should work for most scenarios. For example, Windows Live Mail is built in ASP.NET, with a few Silverlight islands, such as a slide show program that allows you to view photo attachments with enhanced experience (actually most Microsoft created web applications takes this approach).

           3. Will this be a good chance to revise your architecture?

    Most traditional ASP.NET applications use the B/S or three tire architecture, in which the application works with a database either directly, or through a business logic layer. When porting applications to other platforms, these architectures will introduce many problems. When investigating Silverlight, it is also a good chance to adopt SOA. Add a service facade layer on top of the business logic layer, and you can work with the services from almost any client, such as an ASP.NET application and a Silverlight application. If you are already on SOA, it should be trivial to port to Silverlight, since you only need to rewrite a client application. With SOA, the ASP.NET AJAX approach and the Silverlight island approach will also be much easier to implement.

    If none of the above approaches is suitable, you may have to mix Silverlight content with ASP.NET. When using this approach, keep in mind that Silverlight can’t call ASP.NET server side event handlers, and each post back (either partial or complete) will cause the Silverlight application to reload.


     

    10. CLR: [top]

     

    10.1 What do I do when my Silverlight application seems to leak memory? [top]

    While Silverlight has a home-grown mini CLR, the garbage collector works very similar to desktop CLR. Most suggestions for desktop CLR also apply to Silverlight. If you think your application has a memory leak, execute a GC.Collect function call on all generations (0,1,2,3) to verify whether memory usage decreases. Then, check the following:

    • Do you have any opened resource, such as streams? Theseresources won’t be collected.

    • Do you have any large and long living objects? For example, static objects.

    • Do you have any objects implementing finalizer? These objects can’t be collected in a single pass.

    One way to view the managed heap is to use WinDbg. There is a blog post demonstrating how to use WinDbg with Silverlight. Note if you’re on a 64 bit machine, you need the 32 bit WinDbg, or it won’t be able to load Silverlight’s sos.dll since it was compiled to target 32 bit machines.

    After you load the sos.dll, type the command “!eeheap -gc”, and you’ll see something like this:

    Number of GC Heaps: 1

    generation 0 starts at 0x05b4c420

    generation 1 starts at 0x05b3100c

    generation 2 starts at 0x05b31000

    ephemeral segment allocation context: none

             segment            begin         allocated             size

    05b30000 05b31000  05b5242c 0x0002142c(136236)

    Large object heap starts at 0x06b31000

             segment            begin         allocated             size

    06b30000 06b31000  06b368d0 0x000058d0(22736)

    Total Size:              Size: 0x26cfc (158972) bytes.

    ------------------------------

    GC Heap Size:    Size: 0x26cfc (158972) bytes.

     

    You should pay special attention to the large object heap, since that’s where large objects are stored. Now run the command “!dumpheap 06b31000”, where 06b31000 is the address of the large object heap, and you’ll see a list of large objects:

    Address       MT     Size

    06b31000 0486f9a0       16 Free

    06b31010 03e85668     4096    

    06b32010 0486f9a0       16 Free

    06b32020 03e85668      528    

    06b32230 0486f9a0       16 Free

    06b32240 03e85668     4096    

    06b33240 0486f9a0       16 Free

    06b33250 03e85668     4096    

    06b34250 0486f9a0       16 Free

    06b34260 03e85668     4096    

    06b35260 0486f9a0       16 Free

    06b35270 03e85668     4096    

    06b36270 0486f9a0       16 Free

    06b36280 03e85668      528    

    06b36490 0486f9a0       16 Free

    06b364a0 03e85668      528    

    06b366b0 0486f9a0       16 Free

    06b366c0 03e85668      528    

    total 18 objects

    Statistics:

          MT    Count    TotalSize Class Name

    0486f9a0        9          144      Free

    03e85668        9        22592 System.Object[]

    Total 18 objects

     

    In the above sample, we have 18 large objects, 9 of which are object arrays. Since we have just called GC.Collect, we can say most of those objects can’t be collected at that time.

    Now that you have knowledge of what types of large objects can’t be collected, you can check your code and try to find them. One more tip: you can use the !GCRoot command to find references of the large object.

    Finally, don’t include GC.Collect in production code. While a forced garbage collection can release some memory, it may cause the application to be temporarily blocked. This is especially true when a compact is required, which is similar to disk defragment.

    For further reference, you can have a look at this log post.

    10.2 What are the restrictions on mini CLR? [top]

    Since it runs in a sandbox, Silverlight has many security restrictions. You’re likely to encounter more and more restrictions if you want to work on the lower levels.

    The security restrictions in Silverlight CLR includes (but are not limited to):

    • User code cannot work with methods/properties marked as SecurityCritical and SecuritySafeCritical, even if they are public.

    • No Win32/Mac interoperating is allowed.

    • No unsafe code is allowed.

    • Cannot use reflection to access members that you can’t access normally. For example, access private members in another class, access internal members in another assembly, etc.

    I would like to highlight the last restriction, since many people encounter problems with it.

    The particular problem is: They try to data bind to an anonymous type, which failed with a MethodAccessException.

    Imagine you have a ListBox:

    <ListBox x:Name="listBox1" DisplayMemberPath="Name"/>

     

    object[] array = new object[10];

    var query = from o in array select new { Name = "a", Age = 1 };

    this.listBox1.ItemsSource = query.ToList();

     

    Run the application, and you’ll encounter the exception. The cause to this issue is exactly a CLR restriction. Somewhere in the data binding code, which is in System.Windows.dll, it uses reflection to access the property named “Name”. As you know, anonymous types are all internal types. So even if the Name property is public, you won’t be able to access it in an assembly other than your main Silverlight assembly.

    You can simulate this behavior in the following way:

    Write an internal class with a public property:

    internal class Test

    {

             public string Name { get; set; }

    }

     

    Create a Silverlight class library and write a method:

     

    public static object GetValue(PropertyInfo property, object target)

    {

             return property.GetValue(target, null);

    }

     

    In the main assembly, create an instance of the internal object, set a value for the property, and call the method in the external assembly to get the property’s value.

    object obj = Activator.CreateInstance(typeof(Test));

    PropertyInfo property = typeof(Test).GetProperty("Name");

    property.SetValue(obj, "abc", null);

    object value = SilverlightClassLibrary1.Class1.GetValue(property, obj);

    Run the application, and you’ll notice that the SetValue works as expected, because you are setting the value in the main assembly. However, GetValue fails with a MethodAccessException, because you are getting the value in an external assembly.

    Data bind to anonymous types works similar to the above scenario, but System.Windows.dll replaces the external assembly written by you.

    You may notice that if you remove the DisplayName property on the ListBox, no exception will throw. This is because System.Windows.dll will not try to access properties in the anonymous class any more.

    There is no workaround to this issue, you can’t use anonymous types if you want to support data binding.


     

    11. Miscellaneous: [top]

     

    11.1 What should I remember regarding routed events? [top]

    Silverlight 2 doesn’t support all features of WPF.  Regarding routed events, the following features are not supported:

    • Cannot create custom routed event (Although you can create CLR events using RoutedEventHandler, they won’t actually route).

    • Cannot handle events that are marked as handled (will be possible in SL3).

    • No Preview*** events.

    • No class handlers.

    • No RoutedEvent.Source property, but OriginalSource still exists (In WPF, Source and OriginalSource are initially identical, but Source can be modified by code, while OriginalSource is read only).

    • No built-in weak event patterns.

    11.2 What offline capabilities does Silverlight support? [top]

    Silverlight 2 doesn’t support offline scenario out of box. While you can run an html file that contains a Silverlight application from the local file system, there are several restrictions:

    • Cannot access resources in the local file system other than the folder and subfolders the hosting html file is in.

    • Cannot use any web related features, such as calling web service.

    • Cannot access online medias such as images and videos hosted in any web site.

    Silverlight 3 will add more offline capabilities, such as the out of browser feature.

    Another interesting scenario is occasionally connected environment. In such an environment, your application supports both online and offline features. When the internet connection works, you can get the latest data from the internet. When the internet connection is lost, you can still work with data that has been downloaded to the local device. You can modify the data in the local device, and once the internet connection is restored, the local data can be synched to the cloud.

    Silverlight doesn’t offer this capability out of box, but you can use Live Services. It allows you to run a Silverlight application out of the browser, and yet be able to call web services since it’s still in the http protocol. It also supports the above occasionally connected scenario without much effort from your part. The data will be stored in cloud and synched among every device the user owns, such as the Live Desktop in the cloud, a PC, a Mac, and a mobile device.

    11.3 Does Silverlight support web camera and printing? [top]

    Unfortunately, Silverlight doesn’t support web camera yet. You can print the containing web page, which will include the Silverlight application’s content if it is currently visible. Features such as print areas beyond the visible areas in a ScrollViewer are not supported yet.

     

     

    Tuesday, May 12, 2009 4:38 AM