dotMorten

.NET Ramblings, XAML hacking and some GIS endeavors

Silverlight and WPF code reuse pitfalls.

The idea is really great: Write your code once, and reuse it across all your platforms. This is one of the great things about .NET. I can reuse business logic in ASP.NET, Mobile, Desktop, Embedded devices, Phones, Web services and so on. Usually the only difference is the UI that behaves a little different on the various platforms.

With WPF and Silverlight, even the UI code can be reused between Desktop and Web, since Silverlight is a subset of WPF. That means that any Silverlight code should be able to run in a WPF application, right? Well at least that’s what Microsoft keeps telling us, and you will fine numerous blog posts discussing it. However, in reality it’s not that straight forward. I’ve been trying to reuse some Silverlight code in a WPF application, and ran into a lot of headaches. What I found is that Silverlight is NOT a subset of WPF and .NET. It is a completely new framework with the subset as a design goal, but Microsoft made several mistakes, some even so bad that fixing it in either WPF or Silverlight would cause a breaking change. In other cases the XAML syntax is incompatible different. This means that you won’t get around using several compiler conditionals and duplicate XAML files.

Below is a list of some of the things I’ve run into, and I’ll try and add to it if I found more. I you know of more, or find errors or explanation to differences please add comments below.

For code that is only for Silverlight I have declared a SILVERLIGHT compiler conditional. so anything inside a #if SILVERLIGHT block is Silverlight only code, and vice verse if it’s in #if !SILVERLIGHT or #else it’s for WPF.

As a side note, the following blog posts discusses some good practices for reusing the same code files in your WPF and Silverlight projects: Sharing source code between .NET and Silverlight. However it hardly deals with code differences like the ones below.

Loading a bitmap

Loading bitmaps are probably one of the biggest differences in the two frameworks (that I’ve seen). In WPF you must call BeginInit and EndInit, and checking for download errors are very different, which requires you to use two different handlers for handling an image load error.

BitmapImage bmi = new BitmapImage();
#if 
!SILVERLIGHTbmi.BeginInit();
#endif
Image img = new Image();
bmi.UriSource = new Uri(url, UriKind.Absolute);
#if
SILVERLIGHTimg.ImageFailed += new EventHandler<ExceptionRoutedEventArgs>(img_ImageFailed); //Silverlight specific error handler
#else
bmi.DownloadFailed += new EventHandler<System.Windows.Media.ExceptionEventArgs>(bmi_DownloadFailed); //WPF specific error handler
bmi.EndInit();
#endif
img.Source = bmi;

Modifying Animations

WPF is very restrictive when it comes to working with animations. When you initialize the animation, you must use an overload that takes the element you are modifying as well as specifying that its modifiable. Silverlight doesn’t have any of these overloads, and is there fore not required.

#if SILVERLIGHT
myStoryboard.Begin();
myStoryboard.Stop();
#else
myStoryboard.Begin(element, true); //true allows for changing animation later
myStoryboard.Stop(element); //element parameter required when Begin was called with element
#endif

Delay Signing

Silverlight does not support delay signing of your assemblies. This might not be a big issue for you though.

Binding to Dictionary

This is more of a subset limitation, but it’s an annoying one, that is fairly tricky to get around.

In WPF you can bind a Dictionary<string,object> object as simple as :

<TextBlock Text="{Binding Path=MyDictionary.[KeyName]}" />

However in Silverlight you have to create your own value converter:

public class DictionaryItemConverter : IValueConverter
{
   public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
   var dict = value as Dictionary<string, string>;
   if (dict != null)
   {
     return dict[parameter as string];
   }
     throw new NotImplementedException();
   }
   public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
   {
     throw new NotImplementedException();
   }
}

Using the converter you can then bind your dictionary:

<Grid x:Name="LayoutRoot" Background="White">
    <Grid.Resources>
   <local:DictionaryItemConverter x:Name="myDictConvert" />
    </Grid.Resources>
    <TextBlock Text="{Binding Converter={StaticResource myDictConvert}, ConverterParameter=KeyName}" />
</Grid>

(note that you will have to define the local: namespace to point to the namespace/assembly where DictionaryItemConverters is placed).

Value converters are pretty powerful though, so this lesson might come in handy later. This approach does work for WPF too.

Accessing resources declared in XAML from code

Accessing resources you have in your XAML is a common pitfall. If I were to declare a resource in a grid like this:

<Grid x:Name="LayoutRoot">
    <Grid.Resources>
   <local:MyClass x:Key="myResource" />
    </Grid.Resources>
</Grid>

In WPF you would access it like this:

object o = LayoutRoot.Resources["myResource"];

However in Silverlight that would return null! Instead in Silverlight you have to use x:Name instead of x:Key in your XAML:

<local:MyClass x:Name="myResource" />

Unfortunately in Silverlight you can’t declare both a Key and a Name in your XAML (you can in WPF), so you will have to maintain two different XAML files. In WPF you are required to specify a x:Key attribute, so you can’t just make do with the name attribute either.

Control Templates

When you create a control template, you will have to assign the type that the control template belongs to. Here’s the syntax in Silverlight:

<ControlTemplate TargetType="local:MyControl">

And in WPF:

<ControlTemplate TargetType="{x:Type local:MyControl}">

Debug.WriteLine

This one is a little interesting, because it's a method in Silverlight that proves that it’s not necessarily a subset of WPF, since here’s a method that actually have different overloads in Silverlight and WPF. I often use System.Diagnostics.Debug.WriteLine to write out values or warnings that I or the developer should be aware of, but not necessarily is an error.

Here are the overloads in Silverlight:

public static void WriteLine(object value);
public static void WriteLine(string message);
public static void WriteLine(string format, params object[] args); //NOT IN WPF! 

and WPF:

public static void WriteLine(object value);
public static void WriteLine(string message);
public static void WriteLine(object value, string category);
public static void WriteLine(string message, string category); 

Notice that the 3rd method in Silverlight which is equivalent of using string.Format, doesn’t exist in WPF. Therefore always use WriteLine(string.Format(format,args)) instead.

OnApplyTemplate fired in different order

The OnApplyTemplate call on your controls are fired at different times in WPF and Silverlight. This can cause a lot of problems if you rely on certain events to have happened before the OnApplyTemplate event has triggered, or vice versa. This is a case where you have to be really careful with code-reuse in Silverlight and WPF.

In the example below I created a simple sample and ran it in Silverlight and WPF, with breakpoints in each loaded handler, constructor and OnApplyTemplate in my custom control.  The XAML is below (simplified and removed namespace declarations for readability):

<UserControl Loaded="UserControl_Loaded”>     <my:Control Loaded="MyControl_Loaded /> </UserControl>

Order the methods were hit:

  Silverlight WPF
1. UserControl Constructor UserControl Constructor
2. MyControl Constructor MyControl Constructor
3. MyControl Loaded MyControl.OnApplyTemplate
4. UserControl Loaded UserControl Loaded
5. MyControl.OnApplyTemplate MyControl Loaded

See this post for a workaround.

Case sensitivity

Silverlight in general seems less restrictive when it comes to your XAML. For instance case sensitivity. I was recently trying to use a class modifier on my UserControl using the following:

<UserControl x:ClassModifier=”Internal”>

However this doesn’t work in WPF. It turns out that the “internal” keyword must be lowercase in WPF.

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

Jeff Wilcox also has a list of issues that he hit in his gravatar project described in this blog post: http://www.jeff.wilcox.name/2009/03/gravatar-control/

Doubleclicking in Silverlight

Mike Snow recently posted an article on how to do double clicks in Silverlight. However, his approach isn't very reusable, doesn't allow for multiple listeners and doesn't check to see if the mouse moved between the two clicks. Below is my solution, which uses extension methods and attached properties to track clicks and event handlers.

To use it, first include the namespace in your code:

using MyApplication.Extensions;

This will add AddDoubleClick and RemoveDoubleClick methods to any UIElement. You can then add an event handler to your element like so:

MyDblClickElement.AddDoubleClick(MyDblClickElement_MouseDoubleClick);

The double click handler signature is the same as for mouse down. Example:

private void MyDblClickElement_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
Point position = e.GetPosition(this);
MessageBox.Show(string.Format("dblclick at {0},{1}", position.X, position.Y));
} 

Here's the code:

using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;
namespace MyApplication.Extensions
{
public static class Mouse
{
private const int doubleClickInterval = 200;
private static readonly DependencyProperty DoubleClickTimerProperty = DependencyProperty.RegisterAttached("DoubleClickTimer", typeof(DispatcherTimer), typeof(UIElement), null);
private static readonly DependencyProperty DoubleClickHandlersProperty = DependencyProperty.RegisterAttached("DoubleClickHandlers", typeof(List<MouseButtonEventHandler>), typeof(UIElement), null);
private static readonly DependencyProperty DoubleClickPositionProperty = DependencyProperty.RegisterAttached("DoubleClickPosition", typeof(Point), typeof(UIElement), null);
/// <summary>
/// Adds a double click event handler.
/// </summary>
/// <param name="element">The Element to listen for double clicks on.</param>
/// <param name="handler">The handler.</param>
public static void AddDoubleClick(this UIElement element, MouseButtonEventHandler handler)
{
element.MouseLeftButtonDown += element_MouseLeftButtonDown;
List<MouseButtonEventHandler> handlers;
handlers = element.GetValue(DoubleClickHandlersProperty) as List<MouseButtonEventHandler>;
if (handlers == null)
{
handlers = new List<MouseButtonEventHandler>();
element.SetValue(DoubleClickHandlersProperty, handlers);
}
handlers.Add(handler);
}
/// <summary>
/// Removes a double click event handler.
/// </summary>
/// <param name="element">The element.</param>
/// <param name="handler">The handler.</param>
public static void RemoveDoubleClick(this UIElement element, MouseButtonEventHandler handler)
{
element.MouseLeftButtonDown -= element_MouseLeftButtonDown;
List<MouseButtonEventHandler> handlers = element.GetValue(DoubleClickHandlersProperty) as List<MouseButtonEventHandler>;
if (handlers != null)
{
handlers.Remove(handler);
if(handlers.Count == 0)
element.ClearValue(DoubleClickHandlersProperty);
}
}
private static void element_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
UIElement element = sender as UIElement;
Point position = e.GetPosition(element);
DispatcherTimer timer = element.GetValue(DoubleClickTimerProperty) as DispatcherTimer;
if (timer != null) //DblClick
{
timer.Stop();
Point oldPosition = (Point)element.GetValue(DoubleClickPositionProperty);
element.ClearValue(DoubleClickTimerProperty);
element.ClearValue(DoubleClickPositionProperty);
if (Math.Abs(oldPosition.X - position.X) < 1 && Math.Abs(oldPosition.Y - position.Y) < 1) //mouse didn't move => Valid double click
{
List<MouseButtonEventHandler> handlers = element.GetValue(DoubleClickHandlersProperty) as List<MouseButtonEventHandler>;
if (handlers != null)
{
foreach (MouseButtonEventHandler handler in handlers)
{
handler(sender, e);
}
}
return;
}
}
//First click or mouse moved. Start a new timer
timer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(doubleClickInterval) };
timer.Tick += new EventHandler((s, args) =>
{  //DblClick timed out
(s as DispatcherTimer).Stop();
element.ClearValue(DoubleClickTimerProperty); //clear timer
element.ClearValue(DoubleClickPositionProperty); //clear first click position
});
element.SetValue(DoubleClickTimerProperty, timer);
element.SetValue(DoubleClickPositionProperty, position);
timer.Start();
}
}
}

Impressions from Microsoft PDC

I attended the Microsoft PDC in Los Angeles Convention Center this week, and here's a recap of various statements, quotes and sessions that I found interesting.

 

WCF Preconference notes

It looks like a class, it feels like a class, it smells like a class, it works like a class – but it’s a service!

This was a full day seminar on Windows Communication Foundation. It was very cool to see how ordinary looking classes could be turned into WCF services that can be exposed through a multitude of protocols using just two class/method attributes. One of the interesting statements were how .NET had replaced COM 7 years after its introduction, and now 8 years later, WCF is replacing .NET (well at least the part that replaced COM). Or to put it in the presenters word: ".NET as you know it is dead!"

WCF is host agnostic. No difference between hosting on IIS, in-proc, self-hosting, Windows Activation Service etc.

Possible transport protocols: HTTP, HTTPS, TCP, P2P, IPC, MSMQ.
Possible message formats: Plain text, Binary, MTOM.
Security options: None, Transport security, Message security, Authentication and authorizing callers.

WCF is the first platform that provides Interoperability, Productivity/Quality AND Extensibility all at once.

Favorite sessions

I must admit that many of the sessions were a little dissappointing. They were often marked as advanced or expert level, but rarely lived up to that. There were also way too many Twitter demos. But having said that, here are the ones I attended that didn't dissappoint. You can watch them all online by clicking the links next to them or see the whole list of sessions here.

  • TL16: "The Future of C#" by Anders Hejlsberg. My Danish hero and the brain behind C# talks about where C# is headed with upcoming v4 and 5 of C#. View
  • TL49: "Microsoft .NET Framework: Overview and Applications for Babies" by Scott Hanselman. Using a a wide varity of .NET core technologies, Scott takes his BabySmash application and ports it to WPF, Silverlight, Mobile and Surface, in his usual entertaining way. Great demonstration of the power of .NET. View
  • PC06: "Deep Dive: Building an Optimized, Graphics-Intensive Application in Microsoft Silverlight" by Seema Ramchandani. Seema goes through all the gory internal details of how Silverlight works and uses this knowledge to present a great set of tips and tricks to making the performance of your Silverlight applications scream. A must-see if you are doing serious work with Silverlight. View
  • TL26: "Parallel Programming for Managed Developers with the Next Version of Microsoft Visual Studio" by Daniel Moth. Processors are not really getting much faster anymore, but instead we get more and more cores to work with, but this also requires us to start changing the way we make software. The Parallel Framework that comes in .NET 4 makes this task really easy. All I can say is that this framework rocks! View
  • BB24: "SQL Server 2008: Deep Dive into Spatial Data" by Isaac Kunen. Isaac's deep dive on the spatial support in SQL Server (thanks for the plug Isaac :-). View
  • PC29: "Microsoft Silverlight 2: Control Model" by Karen Corby. Good information on how to build reusable, skinnable controls for Silverlight. View
  • PC32: "ASP.NET AJAX Futures" by Bertrand Le Roy. Upcoming features for ASP.NET AJAX. View
  • TL46: "Microsoft Visual C# IDE: Tips and Tricks" by Dustin Campbell. LOTS of great shortcuts and features in Visual Studio that you never knew was there and you wonder how you could ever live without. MUST SEE if you want to be more efficient when coding C# in Visual Studio. View
There were a lot of sessions I didn't make it to, but hopefully I'll get some time to view them online over the next coming weeks. If I see anything more that I like, I'll update this list. If you have watched any good sessions as well, please feel free to mention it in the comments.

 

My favorite comment was Juval Lowy's reaction when he the first time heard that Microsoft was working on the successor to VB6:

Giving VB developers access to a multithreaded environment (VB.NET) is like giving razorblades to babies.

It’s not that C++ developers are better off with C#, but they are more used to seeing blood.

 

Microsoft is already planning a new PDC next year November 17-20, 2009 (unfortunately same place).

IE8beta1 and Silverlight 2.0 beta 1 available

Reporting live from the Mix08 conference in Vegas :-)

Internet Explorer 8 beta1 and Silverlight 2.0 beta1 will be available from today !

IE8 comes with a much improved Developer tool with full debugger and style tracing, CSS2.1 and HTML5 support. You better get testing in IE8, because your existing website might be broken in IE8 (since it now finally follows the standards).

Silverlight will also be available for Mobile, and is supported by Nokia who will add it to their S40 and S60 series. You can already see a mobile silverlight app here: silverlight.weatherbug.com. This app was developed in less than 3 weeks and works cross-platform, cross-browser, cross-mobile, cross...

 

Silverlight managed code vs. JavaScript

I finally had a chance to play with Silverlight today. The managed code capabilities is very interesting, so I set out to create a simple performance tester.

I created two basic managed methods in Silverlight. One that multiplies a number and returns a result, and another that does the same thing a specified number of times:

[Scriptable]
public double Multiply(double a, double b)
{
   return a * b;
}
[Scriptable]
public double MultiplyLoop(double a, double b, int count)
{
   double result = 0;
   for (int i = 0; i < count; i++)
      result = a * b;
   return result;
}

This gives me 3 test-cases to compare:

  • Multiply two numbers n times in pure javascript.
  • Multiply two numbers n times, by calling Multiply(a,b) from JavaScript into managed code n times
  • Multiply two numbers n times, by calling MultiplyLoop(a,b,n) from Javascript into managed code one time.

What I found was:

  • JavaScript is fairly slow to do this (345 ms for 10 millions calculations).
  • Calling a managed method millions of times is VERY slow (IE asked me several times whether I wanted to abort it before it finished)
  • Calling a managed method once and do the looping in managed code is VERY fast (0-2 ms).

The conclusion here would be that you shouldn't have methods in managed code that you call a lot from javascript unless they are process-intensive. There seems to be a big overhead in calling into managed code, but as soon as you are in the managed process, its blazing fast.

You can download my test sample here: SilverlightProject1.zip (18.35 KB)  (requires Orcas beta 1 and Silverlight add-on)

Now on to move all my existing .NET libraries into a Silverlight app... :-)

Getting (re)started with Silverlight and some notes

On my way back from the Mix conference in Vegas I was trying to get one of my WPF/E applications to run on the new Silverlight 1.1alpha. It wasn't as easy as I thought it would be because a lot seems to have changed. I finally figured it out after reading Bryant Likes's blog. He already figured it out and shared the solution (Thanks Bryant!):

If you want to go the "real" route of working with Silverlight 1.1alpha, here's what you need:

I saw two really good sessions on Silverlight and .NET this morning. They are online now, and I really recommend that you watch them:

One of the really neat things are that Silverlight also supports LINQ in the client browser. Part 2 shows a cool example on that and how easy it makes it to work with data. Furthermore you can easily communicate between Browser DOM, Javascript and .NET assembly code which makes for some interesting scenarios. Since .NET excution is 400-1000 times faster than JavaScript, you could have your heavy algorithms inside silverlight, and call them from Javascript. If you don't need the presentation-layer, you could just hide it and have it as a library you utilize from JS.

So what is the main differences between v1.0 and v1.1? v1.1 contains:

  • Everything from v1.0
  • A subset of the .NET 3.5 framework and some extra browser and AJAX specific classes
  • XAML extensibility
  • Control class (for user controls)
  • Sample controls

Currently Silverlight works with Safari, Firefox and IE on both Mac and Windows and soon to be Opera as well. I asked them whether they would also support other platforms like Linux. Basically they didn't have any 'issues' with making that, but were currently not considering it until there is a larger demand for it.

Update: Mono has already announced that they will make sure we get Silverlight support on Linux. COOL!