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.

Wednesday, 14 November 2007

SharePoint - dragging WebParts causes "object required" Javascript error

I have been working with SharePoint quite a bit over the past few months. At Netstore we are building an AA accessible website for our client using XHTML with a CSS based layout.

I recently came across a problem where I had a WebPartZone in a page, and when I tried to drag the webparts around I get the javascript error "Object Required". Fortunately, a bit of googling led me to this post - CSS causes JavaScript error while moving Web Parts in edit mode where I learned the issue is due to the zones being placed in elements with a CSS style of position:relative.

Unfortunately I had to fix the bug to pass UAT so I was left with two options - either change the CSS to remove the relative positioning or try to fix the JavaScript. Given that we were working with HTML/CSS delivered by an external design agency (which I didn't want to mess with) I decided to go with the latter.

The blog entry indicated that the problem lay in a Microsoft function called MSOLayout_GetRealOffset. This function is defined in <12>\TEMPLATE\LAYOUTS\1033\IE55UP.JS. I didn' t fancy changing this file as it would present a deployment nightmare, but fortunately with JavaScript, you can override a global function by just defining it later on in the HTML. Therefore I was able to redefine this function in my master page and fix the error. Here is the new version of the function:

        <script language="javascript" type="text/javascript">
            function MSOLayout_GetRealOffset(StartingObject, OffsetType, EndParent)
            {
                var realValue=0;
                if (!EndParent) EndParent=document.body;
                for (var currentObject=StartingObject; currentObject && currentObject !=EndParent && currentObject != document.body; currentObject=currentObject.offsetParent)
                {
                    var offset = eval('currentObject.offset'+OffsetType);
                    if (offset) realValue+=offset;
                }
                return realValue;
            }
        </script>

So if you ever experience the problem, copy and paste this function into your master page file, anywhere after the SPWebPartManager and it should stop.

Tuesday, 22 May 2007

Running ClickOnce applications in firefox

Here is a useful little Firefox extension which lets you run Microsoft ClickOnce applications: https://addons.mozilla.org/en-US/firefox/addon/1608 Fantastic, no more IE required!

Monday, 30 April 2007

“Default” buttons in WPF and multiple default buttons per page

Most user interface frameworks have the concept of a default button. The default button is the button which is activated when the Enter key is pressed. This is an important aspect for usability. For example, on a search form, most users expect to be able to perform a search by pressing Enter on any form element. If this does not happen as expected, the user gets frustrated as they need to either tab onto the button and press Enter, or use the mouse to click. I think the web has pushed this standard as HTML forms automatically post themselves when the user presses Enter within them. WPF offers the ability to have both Default and Cancel buttons. The Cancel button is activated by pressing the ESC key, although in my opinion this is not quite as common as the Enter button as most users don’t expect to be able to press ESC within forms – only dialog windows maybe. How do default buttons work? There is nothing particularly special going on under the covers when you set a button to be the default button. When the IsDefault property is set, AccessKeyManager.Register is called, passing in “\r” as the access key. Similarly, the act of setting IsCancel calls AccessKeyManager.Register passing in the character code for ESC - “\x001b”. The only special thing that setting IsDefault will do is ensure that the IsDefaulted property is updated correctly. This allows, for example, buttons to be styled differently if they are defaulted. How do I get multiple default buttons per page? In ASP.NET a common problem was that because you are forced to have a single server-side form, it was not possible to have multiple logical forms on the page and have the Enter button behave as expected without a lot of hacking. For example, you might want the template for all your pages to have a small search form at the top with a search button, and also have the search performed when the user presses enter within the search box. When the user is on a page with its own form on it, you would want that form to be submitted when the user pressed enter. This was not possible natively. This issue was solved in ASP.NET2 by allowing any Panel or Table to have set a DefaultButton property. Behind the scenes this would set up an event handler in JavaScript which would activate the button when enter was pressed. In WPF, there is no such property. If you define two panels on a page, and into each panel place a TextBox and a Button with IsDefault="True", you will see that pressing enter in either TextBox always activates the first button. This is because that button registered itself first so is at the top of the invocation list of the Enter access key:

<Window x:Class="WindowsApplication7.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WindowsApplication7"
    Title="WindowsApplication7" Height="300" Width="300"
    >
    <StackPanel>
        <StackPanel Margin="5" Background="Yellow">
            <TextBox Margin="5" />
            <Button Margin="5" IsDefault="True" Content="Yellow" />
        </StackPanel>
        <StackPanel Margin="5" Background="Green">
            <TextBox Margin="5" />
            <Button Margin="5" IsDefault="True" Content="Green" />
        </StackPanel>
    </StackPanel>
</Window>
In the above example, no matter which TextBox has focus, the Yellow button is always activated when you press enter. To solve this problem, there is a fairly undocumented feature within the AccessKeyManager called scoping. This allows you to define a scope for an access key such that it is only activated within that scope. The way this is done is by handling the routed event and adding the scope to the event args. Then when it returns to the AccessKeyManager, it detects that it has been scoped and will only apply it to buttons within that scope. The code is quite simple to write, but I have created a small helper class to encourage readibility and code reuse. In WPF it’s so easy to write small helper classes and seamlessly integrate via the use of attached properties, so I made an attached property called AccessKeyScoper.IsAccessKeyScope which can be applied to any element. With this, the above example simply needs to be modified as follows, and the correct button will be activated:
<StackPanel Margin="5" Background="Yellow" local:AccessKeyScoper.IsAccessKeyScope="True">
    <TextBox Margin="5" />
    <Button Margin="5" IsDefault="True" Content="Yellow" />
</StackPanel>
<StackPanel Margin="5" Background="Green" local:AccessKeyScoper.IsAccessKeyScope="True">
    <TextBox Margin="5" />
    <Button Margin="5" IsDefault="True" Content="Green" />
</StackPanel>
The code for the helper class is here:
using System;
using System.Windows;
using System.Windows.Input;
namespace WindowsApplication7
{
    /// <summary>
    ///    Class used to manage generic scoping of access keys
    /// </summary>
    public static class AccessKeyScoper
    {
        /// <summary>
        ///    Identifies the IsAccessKeyScope attached dependency property
        /// </summary>
        public static readonly DependencyProperty IsAccessKeyScopeProperty =
            DependencyProperty.RegisterAttached("IsAccessKeyScope", typeof(bool), typeof(AccessKeyScoper), new PropertyMetadata(false, HandleIsAccessKeyScopePropertyChanged));
        /// <summary>
        ///    Sets the IsAccessKeyScope attached property value for the specified object
        /// </summary>
        /// <param name="obj">The object to retrieve the value for</param>
        /// <param name="value">Whether the object is an access key scope</param>
        public static void SetIsAccessKeyScope(DependencyObject obj, bool value)
        {
            obj.SetValue(AccessKeyScoper.IsAccessKeyScopeProperty, value);
        }
        /// <summary>
        ///    Gets the value of the IsAccessKeyScope attached property for the specified object
        /// </summary>
        /// <param name="obj">The object to retrieve the value for</param>
        /// <returns>The value of IsAccessKeyScope attached property for the specified object</returns>
        public static bool GetIsAccessKeyScope(DependencyObject obj)
        {
            return (bool) obj.GetValue(AccessKeyScoper.IsAccessKeyScopeProperty);
        }
        private static void HandleIsAccessKeyScopePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (e.NewValue.Equals(true))
            {
                AccessKeyManager.AddAccessKeyPressedHandler(d, HandleScopedElementAccessKeyPressed);
            }
            else
            {
                AccessKeyManager.RemoveAccessKeyPressedHandler(d, HandleScopedElementAccessKeyPressed);
            }
        }
        private static void HandleScopedElementAccessKeyPressed(object sender, AccessKeyPressedEventArgs e)
        {
            if (!Keyboard.IsKeyDown(Key.LeftAlt) && !Keyboard.IsKeyDown(Key.RightAlt) && GetIsAccessKeyScope((DependencyObject)sender))
            {
                e.Scope = sender;
                e.Handled = true;
            }
        }
    }
}