In this post we explore the question, “can it be done ?”
If we were asking “can we write one application that targets both Windows Forms and ASP?”, I would say “sure but there will be little code in common.” The data access and business layer perhaps … if you are careful. At the application, UI, and presentation levels there are irreconcilable differences. Maybe 10% to 20% of the code can be the same in both environments. That’s my opinion based on recent observations of such a case.
I believe the story is much better when it comes to writing a single application with both a Silverlight and a WPF face. It helps enormously that they share the same presentation philosophy, the same UI specification language (XAML), the same client-side execution model, and many of the same components.
According to my calculations for Silverlight v.3, you will be able to re-use between 52.6% and 93.7% of your code-base to support both platforms.
I’m sure you are wondering … why the big spread?
Let’s walk up the application stack and evaluate the opportunities for re-use at each level.
Let us stipulate that we can use the same database regardless of client technology.
This high percentage presupposes that you are prepared to use the same asynchronous server-access in your WPF application that you must use in your Silverlight application. Silverlight only permits asynchronous communications with the server. This means you can’t issue a query and block the UI thread until the data arrive. You must design and develop a user experience that keeps going while the program is waiting for data.
Some argue that this is a good idea anyway. Unfortunately, only a handful of developers have experience writing non-blocking UIs. You should anticipate a slower initial pace of development as the team learns to program in async style.
North of 90% of your non-visual application layer classes can be written once and “shared” between regular DotNet and Silverlight assemblies.
The word “shared” deserves at least passing comment. The DotNet and Silverlight assemblies often look alike but they are not the same. Your Silverlight projects must be compiled against Silverlight assemblies; your WPF projects must be compiled against DotNet assemblies. Obviously you don’t want to duplicate your code. The trick is to arrange for the two kinds of project – Silverlight and WPF – to share the same physical code files. You can do this manually in Visual Studio but it is far more convenient to use the Project Linker from Microsoft Patterns and Practices.
Rocky Lhotka presented techniques for coordinating bi-platform development in his Tech Ed 2009 talk “WUX313 Sharing Code between Your Microsoft .NET Framework Applications and Microsoft Silverlight”; I hope a public link to his talk becomes available soon; you can always ask Rocky for it.
You can rely on Prism to glue your application together because Prism was built to support multi-platform scenarios.
XAML is the Problem
It is the visual classes – the XAML files in particular – that present a significant challenge.
There is no issue if you’ll have one look for Silverlight and a different look for WPF. The Model-View-ViewModel pattern makes it easy to share the non-visual Model and ViewModel classes across platform; all you have to do is whip up your separate View XAML files and – shazam! - you’re done.
Did he really say “whip up your separate XAML files …”? He’s got to be kidding!
Yes I am kidding. Unless you’re auto-generating your views (which I cannot recommend), you will invest heavily in crafting XAML that both looks good and enhances user productivity.
If you decide to produce different views for each platform – and there are strong arguments for doing so – you’ve just identified the 50% of your application (measured in effort if not in kilobytes) that will differ across platform.
On the other hand, if you intend to use the same views – the same XAML – on both platforms, you can hope for 90+% XAML re-use, thus bringing your total for the application to the coveted 93.7% mark.
So there’s the spread: 50% common code if you have separate views and 90+% if you have shared views. No brainer, right?
Not so fast. The effort and compromises essential to re-use XAML can be daunting. WPF and Silverlight XAML are similar but maddeningly different in critical details. I won’t explore these differences in depth here but I will call out a few of the obstacles.
First, there are many features in WPF that don’t exist in Silverlight 3. Implicit styling is one example but there are numerous others. Because WPF is (mostly) a superset of Silverlight, if you design for Silverlight you’ll have a better chance of retargeting the XAML for WPF.
Second, there are features of Silverlight 3 that are not yet in WPF-proper such as the DataForm. It will show up eventually but you’ll have to wait for it.
Third, some of the features available on both platforms happen to be declared in different namespaces; Shawn Burke posted about this back in November 2008 and I don’t believe the incompatibilities have been resolved in Silverlight 3. If I recall (to be confirmed) the VisualStateManager is one crucial example of a component that is not in the same namespace on both platforms.
As it happens, you can define a namespace that doesn’t exist in your XAML file as long you don’t reference it. Your app will build and run fine with a phantom namespace declaration such as xmlns:dummy="dummy". You might think this would provide some relief. You could define one prefix to refer to the WPF namespace and and a second prefix to refer to the Silverlight namespace. But which prefix do you use when you want to declare a VisualStateManager? You can’t toggle prefixes.
Fourth, XAML does not support compiler directives (#if/#else/#endif), namespace aliasing, or partial class files. Why does this matter? Because we use all three of these techniques to manage the inevitable differences between WPF and Silverlight implementations … when managing such differences in code.
If XAML supported compiler directives, for example, we could work around the dueling namespace prefix problem with something like this:
<!-- This does not work! -->
You can find a XAML pre-processor that will recognize and resolve compiler-like directives in XAML. Sadly, you won’t be able to use the visual design tools (e.g., Blend) because they won’t recognize or honor the directives.
I hope you will join me in asking Microsoft to make support for conditional XAML a priority.
Netting It Out
It is reasonable to contemplate writing a single application that sports both a WPF and Silverlight client experience.
It isn’t automatic. Microsoft could make it easier … and eventually will. But the important take away is that you can do it and it is relatively easy today if you are willing to write distinct Silverlight and WPF XAML files.
In a future post we’ll talk about who wants to write a WPF+Silverlight application and why.