Saturday 22 March 2008

Silverlight projects vs. normal projects, and how to convert a normal project to a Silverlight project

For those of you that use the Silverlight tools for Visual Studio, you have probably tried adding a reference from a Silverlight project to another non-Silverlight project in the same solution, just to see what happens. If do so, you will be met with the following message:



Or if you try to do it the other way round:



Why is this? Well, Silverlight uses different CLR to the rest of .NET, known as the CoreCLR. The CoreCLR is a stripped down version containing only the stuff deemed necessary by the Silverlight team. Also, if you look at the version number of any of the Silverlight assemblies (e.g System.Xml) you will see that the version is 2.0.5 whilst the version of System.Xml in a non-Silverlight assembly is 2.0.0. They are not binary compatible.

So imagine the situation where you have a class library which you wish to build for Silverlight consumption. There are two solutions:

1. Create a new Silverlight class library, and add all the class files to the project. This is fine for a small project.

2. Edit the .csproj file manually, and convert it to a Silverlight project. This is good if you have a large project with lots of file and subdirectories.

I originally looked into this because I wanted to convert to the Ninject.Core, a lightweight dependency injection framework (www.ninject.org), to Silverlight. It wasn't too hard - here are the steps to do so:

- Add the following lines in the first <PropertyGroup> section:

  <ProjectTypeGuids>{A1591282-1198-4647-A2B1-27E5FF5F6F3B};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
<SilverlightApplication>false</SilverlightApplication>
- In the DefineConstants section, add a define for SILVERLIGHT and clauses to specify not to build against standard libraries, e.g
  <DefineConstants>TRACE;DEBUG;SILVERLIGHT</DefineConstants>
<NoStdLib>true</NoStdLib>
<NoConfig>true</NoConfig>
- Change <Reference include="System"> to <Reference include="system">

- Add the following lines right at the end (just before the </project> tag)
  <ProjectExtensions>
<VisualStudio>
<FlavorProperties GUID="{A1591282-1198-4647-A2B1-27E5FF5F6F3B}">
<SilverlightProjectProperties>
</FlavorProperties>
</VisualStudio>
</ProjectExtensions>
Hope this helps
Neil

Friday 21 March 2008

Very simple ICommand implementation for Silverlight

One thing lacking the current Silverlight Beta 2 release is an ICommand implementation. "Commanding" is one of my favourite features of WPF. The idea is that any command source (such as a button) can be bound to a command and that command will be executed whenever the command source is activated (e.g. the button is clicked).

WPF's ICommand interface features the following three members:

Execute(object parameter) - Called whenever the command is activated. The parameter is optional.

CanExecute(object parameter) - This method is called to determine whether the command can execute at the current time. The main feature of this is the command source can disable itself if its command cannot be executed.

event CanExecuteChanged - The command should raise this event whenever it's ability to be executed has changed.

One advantage of commands over standard event handlers is that they allow you to place your event handling implementation outside of your "code behind" class and handle commands in a more generic fashion. This is a key part of implementing the Model-View-ViewModel pattern, which I am trying to implement for my Silverlight application (more to follow on this).

Note that WPF takes commanding a step further than just the ICommand interface, providing us with the RoutedCommand implementation. I won't go into detail about Routed Command here, as Josh Smith already has a great post about them, in which you will understand the advantages of using them over standard ICommands.

Anyway, I digress... back to Silverlight! The important thing here is that I wanted to use commands when developing for Silverlight, and there is nothing available. I made the choice to knock something together very quickly to solve this issue, making use of Attached Properties to bind the commands source (currently only ButtonBase derivatives are supported) to ICommand implementations. I could have spent A LOT more time on this, but I figure that commands are such a key part of WPF that they will soon make their way into Silverlight rendering my code fairly redundant!

I decided to place my code into a Silverstone (random name I know!) assembly, which you can download here. Add the project to your solution and compile it. Now lets create a simple command which just alerts a message:

using System;

using System.Windows.Browser;

 

using Mosafi.Silverlight;

 

namespace WindowsApplication1

{

    public class TestCommand : ICommand

    {

        public event EventHandler CanExecuteChanged;

 

        public bool CanExecute(object parameter)

        {

            return true;

        }

 

        public void Execute(object parameter)

        {

            HtmlPage.Window.Alert("The TestCommand was Executed");

        }

    }

}

That's the command defined, now we need to create an instance somewhere. One would often place all related commands in a single static class, and reference them in XAML using the {x:Static} markup extension. However Silverlight doesn't have this extension, so we will put them in the Resources and use the {StaticResource} markup extension instead. Here is how to create a page with a button which executes the command when clicked:

<UserControl x:Class="WindowsApplication1.Page"

   xmlns="http://schemas.microsoft.com/client/2007"

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

   xmlns:mosafi="clr-namespace:Mosafi.Silverlight;assembly=Mosafi.Silverlight"

   xmlns:WindowsApplication1="clr-namespace:WindowsApplication1">

 

    <UserControl.Resources>

        <WindowsApplication1:TestCommand x:Key="TestCommand" />

    </UserControl.Resources>

 

    <Button Content="Execute Test Command"

            Width="100"

            HorizontalAlignment="Left"

            mosafi:CommandBinder.Command="{StaticResource TestCommand}" />

</UserControl>

DISCLAIMER: In no way is this a fully featured implementation of Commanding, and I would not recommend using it in a "production" system (the reason being that the command handlers may hold onto the buttons indefinitely and stop them from being garbage collected). However it should make the transition to any forthcoming Microsoft command implementation much easier.

Any feedback much appreciated.

Hope this help

Neil

UPDATE: This code has been moved into the Silverstone framework

Thursday 13 March 2008

ASP.NET Ajax - Number.format doesn't round

I recently came across an annoying inconsistency between Decimal.ToString()/String.Format() on the server, and Number.format()/Number.localeFormat() on the client javascript. The client code doesn't round!

Try it yourself. Open firebug on an ASP.NET Ajax website (this one will do), open the Console, and type

123.456.format("N2")

This simple line of code tells it to format the string as a decimal to 2 decimal places. The resulting output, 123.45, is WRONG!

Try this using .NET on the server 123.456.ToString("N2") and you will get the correctly rounded value - 123.46.

How to fix this? As I have pointed out before, with JavaScript, you can override any function by just defining it later on in the HTML. So I created a new script file with a new definition of the Number._toFormattedString() method, which is the private method used to do the formatting. I then include this file in the <scripts> of my ScriptManager on the master page. Script references are always loaded after ASP.NET Ajax internal scripts itself.

It's not that hard to fix - you just have to apply some rounding logic to the existing code, which features the following line:

if (rightDifference > 0) {

  right = right.slice(0, precision);

}

This just slices the end of the string off and doesn't even consider doing any rounding!

Now there are many ways to perform rounding which I won't go into here, but if you want to check it you can download the replacement script here. Simply include this in an <asp:scriptreference> in the scripts section of your script manager and rounding should work fine.

Hope this helps.

Wednesday 12 March 2008

Prism - New CAB/MVC style framework for building WPF applications

About a year ago Microsoft's patterns and practices team released Acropolis as a beta - a UI framework for building WPF applications using a MVC style approach. I played around with it but to be honest I didn't feel it was advanced enough for building fully fledged business applications, but a very good start.

For the National Express project we gradually applied the MVVM (Model-View-ViewModel) pattern, which we fully crafted by hand. Obviously it was a learning experience but it worked well and fitted in well with WPF. Also as we crafted it by hand we had full control of pretty much everything going on in the application and could refactor as we pleased.

Well the Acropolis framework development project was halted about six months ago, after much user feedback. The patterns and practices team have been working on a new CAB style framework, codenamed Prism (not to be confused with Mozilla's Prism project, which integrates web applications with the desktop) . Briefly looking at it, it does remind me of the existing composite application frameworks developed by that team - namely Web Client Software Factory for ASP.NET MVP applications, and the Composite Application Blocks for building WinForms applications.

I have to say I like the approach. This feels very familar for those of us that have used either of these two frameworks, which can only be a good thing and helpful for those architecting WPF applications who have come from a WebForms/WinForms background. It will help in increasing the adoption of WPF applications for the business/enterprise.

The team have released a reference implementation - a stock trader application. Download it here and read the blog post which provides more details about the reference implementation.