Monday, March 17, 2008

Tips for converting from Silverlight 1.1 Alpha to 2.0 Beta

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/tips_for_converting_from_silverlight_11_alpha_to_20_beta.htm]



As I convert some Silverlight 1.1 Alpha apps to the new 2.0 Beta, I'm running across a lot of issues. So far, all have been solvable. Besides the breaking changes documented on MSDN, here are some others. Also, check the Silverlight Bugs forum if something just doesn't appear to be working right.

Silverlight app does not appear to automatically clip an object moving outside the canvas. I.e. if you define a canvas at 100 x 100, and place an image at (200,200), it will still show up. This can be a problem for widgets with moving parts, especially if the location for those parts are based on complex rules (i..e. the physics engine for a game). You can solve this by having your html host page explicitly set the Silverlight apps' boundaries (instead of using percentages):

            <object data="data:application/x-silverlight," type="application/x-silverlight-2-b1" width="300" height="400">

Image source uses strongly typed bitmap instead of a string url source. You can still dynamically load images.

Downloading xml files by default is now asynchronous. This quickstart tutorial explains how to download files. Sure, it is often a good practice to download the file asycnh so that you do not block the main UI thread. But, for small "legacy" apps that you just want to convert quickly, which download small files from the same server as the silverlight app (i.e. no cross domain), where security is not an issue - it's nice to just have a quick synch method to download files. JackBond wrote a good wrapper utility to get around this, re-pasted here for convenience:
//Method from JackBond at: http://silverlight.net/forums/t/11508.aspx
public static string DownloadXmlStringSync(string url)
{
  ScriptObject request;
  request = HtmlPage.Window.CreateInstance("XMLHttpRequest");

  request.Invoke("open", "GET", url, false);
  request.Invoke("send", "");

  return (string)request.GetProperty("responseText");
}
The source for relative paths has changed, especially when referenced from a user control. Before, relative paths were referenced from root directly. Now, they appear to be referenced from ClientBin (I think). One easy work around is to always just convert your relative paths to absolute ones.

UserControls are no longer just Canvases. This is good and bad.
  • The good is that you now have strongly-typed names for all your controls. No more calling this.GetType().Assembly.GetManifestResourceStream, and then doing (root.FindName("TxtMessage") as TextBlock).Text = strText. Rather, you can just say this.TxtMessage.
  • The Bad is that (at least to my understanding) you cannot make a base class that all your UserControls inherit from. Normally (like in ASP.Net or with 1.1 Alpha Canvases), you could make MyBase which derives from Control, and then have all your custom controls inherit MyBase. But now in Silverlight, you cannot do this because the generated partial class from the Xaml hard-codes a reference to UserControl, and that locks you in. Although, I hope I missed something there, or it's changed in the next beta, because using abstract base classes obviously has its benefits.
Practically, I found it easiest to just delete my Canvas files, and then re-create a UC with the same name, and then manually copy the old canvas code back in.

Reminder: Storyboard needs to be started from Page_Load, not the constructor. Thanks to Bill Reiss for pointing this out. While not a breaking change, it's a good reminder. Before, a Silverlight User Control (i.e. based on the Canvas element) had a Page_Load event, so you could start your StoryBoard from that. But now, the UserControls have a constructor. So, you'll need to add the Load event, and then start your story board from that. Else, you'll waste time like I did wondering "why doesn't this storyboard start?"

Clicking a button, and then making that same button invisible in its click event, causes an exception. More documented on the forums. One suggestion is to set the size to 0.

Third Party controls may mess up your references. If you were using 3rd party controls, it may mess up your name spaces and you get a "Cannot find that type" error. For example, I used a 3rd party button control, and then it could no longer find the new Beta 2.0 buttons, so I kept getting a "Cannot find class or namespace Button...." compile error. I needed to manually add this to the csproj file in the <ItemGroup> for the References:
       
    <Reference Include="System.Windows.Controls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

Application_Exit unexpectedly hit by attaching the mouseHandler to a canvas. It's hard for me to describe this one. But, if you're walking through some mouse-handling code where you attach and detach it, or call the GetPosition on a target canvas that's been removed from the Page , it may throw an exception. I know that's ambiguous, but it's something I was seeing.

No comments:

Post a Comment