Monday 28 July 2008

Microsoft Sponsors Open Source Apache

Given that Microsoft have invested lots of time and money in their own web server (IIS), this is a true endorsement of changes afoot at Microsoft http://news.bbc.co.uk/1/hi/technology/7528857.stm

I personally think this makes complete sense for them. I truly believe as we move to a more service delivered software models, the value of source code (or software IP) becomes less important, as licence revenue becomes less of a percentage of total revenue for the big boys such as MS.

For companies like Microsoft, interoperability is very important and its relevance is definitely growing. For example, I am sure that to allow users to be able to transfer services currently running on a LAMP architecture to run on Microsoft's own hosted Windows "cloud" architecture is going to be important for them in future (even if it's not running on a .NET platform). Here is some more detailed info

Interestingly enough, their competitor Apple seems to be going in the other direction with their iPhone SDK, for which the licence agreement apparently does not allow people to build open source software... hmm!

Wednesday 23 July 2008

Is INotifyPropertyChanged an anti-pattern?

Something is starting to bother me recently about data binding and the INotifyPropertyChanged interface. It's just that EVERY class you write ends up having to implement it (I am generally talking about writing WPF/Silverlight applications here). And that's just not sitting well with me!

It doesn't sit well because I believe it violates the principles of separations of concern. The major annoyance for me lies with calculated properties (those which are derived from another). Lets start with a simple class, Order, which contains two properties, ItemPrice and Quantity (other fields and methods omitted for sake of brevity):

public class Order : INotifyPropertyChanged
{
  public decimal ItemPrice 
  { 
    get { return this.itemPrice; }
    set 
    {
       this.itemPrice = value;
       this.RaisePropertyChanged("ItemPrice");
    }
  }

  public int Quantity 
  { 
    get { return this.quantity; }
    set 
    {
       this.quantity= value;
       this.RaisePropertyChanged("Quantity");
    }
  }
}

We need to add a property TotalPrice to this entity which will expose the total price of the order. What do we do here? This is a calculated value so should clearly be read only, and I usually implement the calculation within the property itself. What I have found myself doing many times in the past (and I have seen done in a lot of examples) is:

public class Order : INotifyPropertyChanged
{
  public decimal ItemPrice 
  { 
    get { return this.itemPrice; }
    set 
    {
       this.itemPrice = value;
       this.RaisePropertyChanged("ItemPrice");
       this.RaisePropertyChanged("TotalPrice");
    }
  }

  public int Quantity 
  { 
    get { return this.quantity; }
    set 
    {
       this.quantity= value;
       this.RaisePropertyChanged("Quantity");
       this.RaisePropertyChanged("TotalPrice");
    }
  }

  public decimal TotalPrice
  {
    get { return this.ItemPrice * this.Quantity; }    
  }
}

This is nasty. We have had to modify our other two properties just because we have added this new one. It works, but as you add more and more dependent properties your code gets messy. Those properties shouldn't need to know that the TotalPrice property exists!

That pattern breaks down completely when you start using inheritance in your domain objects. Imagine if I now require a new type of domain object, SalesOrder, where I want to express the fact that there is a commission (expressed as a fraction) which needs to be paid to some salesperson on this order:

public class SalesOrder : Order
{
  public decimal SalesCommision
  { 
    get { return this.salesCommision}
    set 
    {
       this.salesCommisionPercentage = value;
       this.RaisePropertyChanged("SalesCommision");
       this.RaisePropertyChanged("TotalCommission");
    }
  }

  public decimal TotalCommission
  { 
    get { return this.TotalPrice * this.SalesCommission; }
  }
}

Uh-oh! It's come a bit unstuck here. If the price changes in the base class, my UI is not going to redisplay the total commission! This could be great for my sales person but not so great for my accountant!

So what do we do here to get around this? We clearly can't modify our base class, so how about we listen to our own property notifications, like thus:

public class SalesOrder : Order
{
  // Properties defined as previously //

  protected override void RaisePropertyChanged(string propertyName)
  {
     base.RaisePropertyChanged(propertyName);
     if (propertyName == "TotalPrice")
     {
        this.RaisePropertyChanged("TotalCommission");
     }
  }
}

Here we override the method which raises the event, check if the relevant dependent property is being raised, and if so we raise a changed event on our commission property. This works, but YUCK! Just imagine having to unit test all this! :-(

Note that we end up with the same problem if we use composition. Imagine that instead of storing the sales commission on our entity, it was actually stored on a related SalesPerson entity and we need to calculate it from there. Now we need to know that if the sales person's commission changes, the order's total commission has changed:

public class SalesOrder : Order
{
  public SalesPerson SalesPerson
  { 
    get { return this.salesPerson; }
    set 
    {
       if (this.salesPerson != null)
       {
          this.salesPerson.PropertyChanged -= HandleSalesPersonPropertyChanged;
       }

       this.salesPerson = value;
       this.RaisePropertyChanged("SalesPerson");
       this.RaisePropertyChanged("TotalCommission");

       this.salesPerson.PropertyChanged += HandleSalesPersonPropertyChanged;
    }
  }

  public decimal TotalCommission
  { 
    get { return this.TotalPrice * this.SalesPerson.Commission; }
  }

  protected virtual void HandleSalesPersonPropertyChanged(object sender, PropertyChangedEventArgs e)
  {
     if (e.PropertyName == "Commission")
     {
        this.RaisePropertyChanged("TotalCommission");
     }
  }
}

We subscribe to the PropertyChanged event on our sales person, and when its commision is changed, we act accordingly.

I think this is all a mess, and it just gets worse and worse as you build up your domain model and add more classes and more relations. It's easy to forget one of these dependencies. If you are building a fairly complex UI on top of this (e.g. one which allows you to drill down and navigate through the relationships and make changes to objects), I'm so sure you will introduce bugs due to not raising the event, I know it's happened to me!

On my next (real) WPF project this is definitely something I will be thinking about seriously.

Anyway I would be interested to know what people think about this. Is this a problem which other people have faced? How do you architect your applications to avoid this complexity?

Saturday 19 July 2008

Refactoring Silverstone - Removing static container and cleaning up the Shell

Hey readers, hope all is good! Firstly to apologise on having been fairly quiet on the Silverstone / Silverlight blog postings, especially with regards to my series on architecting Silverlight applications using the MVC patterns (most recent article here).

So, Silverlight Beta 2 came out and I spent some time absorbing those changes and trying to work out how they affect what I was doing. I have also made some alterations to the Silverstone framework to remove some code smells I was experiencing when wiring the Views and ViewModels together in preparing part 4 of the series.

One thing that Beta 2 adds is much better support for bubbling of RoutedEvents. This is a great change, but it actually caused a problem for my CommandManager class! The CommandManager was relying on the mouse and keyboard events bubbling up from their target element to the application root in order to provide automatic invalidation of the CanExecuteChanged handler on registered commands. Now that Silverlight has more advanced handling of these events, they no longer bubble up to the application root (as the textbox/button/whatever marks them as e.Handled=true). This is the correct behaviour and mirrors WPF, but it means my technique no longer works, making the ViewModels slightly more complex as they need to manually raise the CanExecuteChanged event.

Once Silverlight gets event tunnelling, which I'm sure (hope!) will be incorporated into the next release, I will add this back in as we will be able to capture the events before they are actually handled by the target element (e.g. PreviewKeyDown / PreviewMouseDown).

So I now have a basic view working, and will be creating the other views soon and blogging the next part in the near future.

As I mentioned, whilst working on this, I made a few refactorings to Silverstone (and to the sample code):

The Ioc Container is no longer a static class. This always bothered me - why have a static class here? So I made it a non static and also made it implement an interface (IContainer). The added bonus of this (and the real reason I did it) is that other components can access the container without going through a static reference. So, the container now registers itself with itself, and you can get it passed to your class simply by adding a constructor parameter of type IContainer.

Once I did that, I refactored the Shell class, which was looking rather nasty from the client API side of things! If you remember in Part 2 of my series, I was writing a LoginViewModel but I was having to pass the other related views into the constructor in order that I could navigate to them upon certain actions (see the comments saying This is just an empty view interface for now *shudder*). I think having to do this makes iterative development much harder as you need to create fakes and register them with the Ioc container just to have your class be constructed!

So instead, the Shell now uses the IContainer to get the views from it and all I need to do is pass the type of the View interface to the Shell and it can do everything from there, like so:

this.shell.Navigate<IFriendListView>();

Finally, I moved the entire sample code into the actual Silverstone SVN repository, which makes it much easier for me to develop the two things side by side! So if you want to an early preview of the code, you can get it from svn

I will be posting the entire solution once it's finished, and hopefully uploading it to some hosting area in the cloud.

Wednesday 9 July 2008

An unmanaged version of WPF coming?

This sounds incredibly interesting - it appears Microsoft are working on what looks like a native version of WPF!

Anyone heard about this or know any more about this - I would love to know some details! An unmanaged version would be great and would probably yield massive performance issues even for unmanaged WPF as a lot of the grunt work would presumably be able to be pushed to unmanaged code.

Could this be the return of the Microsoft's old Cairo project (which now seems to be being worked on by an external group of developers if I'm not mistaken - www.cairoshell.com)

Thoughts?

Sunday 6 July 2008

Using Linq's Expression Trees to Enable Better Refactoring

How many times have you seen code like this:

public DateTime StartDate
{
  get { return this.startDate; }
  set
  {
    this.startDate = value;
    this.RaisePropertyChanged(this, "StartDate");
  }
}

I know I have! There are many areas of .NET development where you are required to specify the name of a property or method as a string. This is fine, but if you rename the property, there is a chance that you will forget to update the string too, which is definitely not good!

.NET 3.5 and Linq introduces a new feature called expression trees in the C#3 compiler. Compilers typically generate an AST (abstract syntax tree) from the code you write, which is then checked and transformed into machine code (or in .NET case, MSIL). By using an expression tree, you tell the C# compiler not to compile your code into MSIL, but instead to create a representation of the code in object form. This tree can then be navigated through methods on the Expression objects.

Using an expression tree, we can simply write a method which will return the name of whichever method or property is being called (I used an extension method):

public static class Extensions
{
    public static string GetPropertyName<T,S>(this T obj, Expression<Func<T,S>> expr)
    {
        return ((MemberExpression) expr.Body).Member.Name;
    }
}

To call this is fairly simple, we rewrite the previous code as:

public DateTime StartDate
{
  get { return this.startDate; }
  set
  {
    this.startDate = value;
    this.RaisePropertyChanged(this, this.GetPropertyName(p => p.StartDate));
  }
}

The code above creates a lambda which returns the value of StartDate method and passes it to the GetPropertyName() method. If this lamdba was to be executed, it would return the startDate, however the GetPropertyName() function never executes the lambda, it simply peeks into the code being called and returns the name of the property.

This technique is starting to be used everywhere and it's so useful. Code as strings is nasty!

Have a great day...

Selecting the Detail Level to View at Runtime in WPF - An even better way!

Regarding my previous post Josh rightly commented that this technique could lead to lots of extra visuals being created that are never displayed, which for large data loads is not desirable and definitely a waste of resources. Josh also made a number of other salient points which are worth reading.

Well it was upon reading this comment that it struck me that there was in fact no need to be creating (and hiding lots of visuals) when they are not used! We simply need a SINGLE content presnter, and just change the template of that with a trigger, like so:

  <DataTemplate x:Key="SelectorTemplate">
    <Grid>
      <ContentPresenter x:Name="proxyDataPresenter" Content="{Binding}" />
    </Grid>
    <DataTemplate.Triggers>
      <DataTrigger Binding="{Binding ElementName=detailLevelSlider, Path=Value}" Value="1">
        <Setter TargetName="proxyDataPresenter" Property="ContentTemplate" 
                Value="{StaticResource LowTemplate}" />
      </DataTrigger>
      <DataTrigger Binding="{Binding ElementName=detailLevelSlider, Path=Value}" Value="2">
        <Setter TargetName="proxyDataPresenter" Property="ContentTemplate" 
                Value="{StaticResource MediumTemplate}" />
      </DataTrigger>
      <DataTrigger Binding="{Binding ElementName=detailLevelSlider, Path=Value}" Value="3">
        <Setter TargetName="proxyDataPresenter" Property="ContentTemplate" 
                Value="{StaticResource HighTemplate}" />
      </DataTrigger>
    </DataTemplate.Triggers>
  </DataTemplate>

The simplicity baffles me and it really works a treat... again this kind of thing just makes me appreciate the sheer power of WPF and it's declarative style of programming.

Saturday 5 July 2008

Selecting the Detail Level to View at Runtime in WPF - An alternate way?

I recently read Josh Smith's post on codeproject which explained how to use a Slider control to dynamically apply a WPF data template a runtime. If you haven't read it, I suggest you read it before continuing.

So I have come up with an alternative solution which is done in pure XAML. This is a technique which I have used on previous projects and it involves creating a "surrogate" data template which simply passes control to another data template via a content presenter. Because a data template is used to do this, it has access to the inheritance context so does not require any freezable hacks to find the slider or other data templates.

Note that in order to make this a pure xaml solution I replaced the data source (which was originally in code) with an XmlDataProvider nested in the XAML document. Hence that lovely Pam girl does not appear in my version, which will probably disappoint most people...

Anyway check it out below, simple copy and paste in XamlPad/Kaxaml to see it working!

<Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <DockPanel>  
    <DockPanel.Resources>
    
      <XmlDataProvider x:Key="Data" XPath="/people">
        <x:XData>
          <people xmlns="">
            <person name="Neil" age="29" gender="M" />
            <person name="Jane" age="40" gender="F" />
            <person name="Jack" age="23" gender="M" />
          </people>
        </x:XData>
      </XmlDataProvider>        
    
      <DataTemplate x:Key="LowTemplate">
        <TextBlock Text="{Binding XPath=@name}" />
      </DataTemplate>
    
      <DataTemplate x:Key="MediumTemplate">
        <TextBlock>
            <TextBlock Text="{Binding XPath=@name}" />
            <Run>(</Run>
            <TextBlock Text="{Binding XPath=@age}" Margin="-4,0" />
            <Run>)</Run>
          </TextBlock>
      </DataTemplate>
    
      <DataTemplate x:Key="HighTemplate">
        <TextBlock>
          <TextBlock Text="{Binding XPath=@name}" />
          <Run>(</Run>
          <TextBlock Text="{Binding XPath=@age}" Margin="-4,0" />
          <Run>) -</Run>
          <TextBlock Text="{Binding XPath=@gender}" />
        </TextBlock>
      </DataTemplate>
      
      <DataTemplate x:Key="SelectorTemplate">
        <Grid>
          <ContentPresenter x:Name="lowPresenter" 
                Content="{Binding}" ContentTemplate="{StaticResource LowTemplate}" 
                Visibility="Collapsed" />
          <ContentPresenter x:Name="mediumPresenter" 
                Content="{Binding}" ContentTemplate="{StaticResource MediumTemplate}" 
                Visibility="Collapsed" />
          <ContentPresenter x:Name="highPresenter" 
                Content="{Binding}" ContentTemplate="{StaticResource HighTemplate}" 
                Visibility="Collapsed" />
        </Grid>
        <DataTemplate.Triggers>
          <DataTrigger 
                Binding="{Binding ElementName=detailLevelSlider, Path=Value}" 
                Value="1">
            <Setter TargetName="lowPresenter" 
                       Property="Visibility" 
                       Value="Visible" />
          </DataTrigger>
          <DataTrigger 
                Binding="{Binding ElementName=detailLevelSlider, Path=Value}" 
                Value="2">
            <Setter TargetName="mediumPresenter" 
                       Property="Visibility" 
                       Value="Visible" />
          </DataTrigger>
          <DataTrigger 
                Binding="{Binding ElementName=detailLevelSlider, Path=Value}" 
                Value="3">
            <Setter TargetName="highPresenter" 
                       Property="Visibility" 
                       Value="Visible" />
          </DataTrigger>
        </DataTemplate.Triggers>
      </DataTemplate>
      
    </DockPanel.Resources>
      
    <StackPanel 
      DockPanel.Dock="Bottom" 
      Background="LightGray"
      Margin="4" 
      Orientation="Horizontal"
      >
      <TextBlock 
        Margin="2,0,4,0" 
        Text="Detail Level:" 
        VerticalAlignment="Center" 
        />
      <Slider 
        x:Name="detailLevelSlider"
        DockPanel.Dock="Bottom" 
        Minimum="1" Maximum="3" 
        SmallChange="1" LargeChange="1" 
        IsSnapToTickEnabled="True" TickFrequency="1"
        Value="0" 
        Width="120" 
        />
    </StackPanel>
    
    <ScrollViewer>
      <ItemsControl
        ItemsSource="{Binding Source={StaticResource Data}, XPath=person}"
        ItemTemplate="{StaticResource SelectorTemplate}"
        />
    </ScrollViewer>
    
  </DockPanel>
</Page>

Saturday 21 June 2008

Silverlight 2.0 Beta 2 - Update on creating a user control to be used as a base class

It appears I was wrong in my previous post.

The ContentPropertyAttribute is seemingly ignored! Although it compiles, and can be edited in Blend, you get a XamlParseException when you try to run it:

"ShellBase does not support Grid as content"

The solution is to manually specify the content property in your Xaml (which kind of sucks!). Strange as this all used to work in Beta 1 (although there were other issues involving namespace parsing which have now been fixed). The correct Xaml looks like this:

<Silverstone:ShellBase x:Class="Silversocial.Client.Views.Shell"

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

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

   xmlns:Silverstone="clr-namespace:Silverstone;assembly=Silverstone">

    <Silverstone:ShellBase.Content>

        <Grid Background="#FF000000">

 

        </Grid>

    </Silverstone:ShellBase.Content>

</Silverstone:ShellBase>

I think (hope) this may be a bug but I will try to confirm this and update my blog if I find out any more.

Thursday 19 June 2008

MessageBox.Show in Silverlight

Well, it's kind of obvious to anyone that has done any browser based Javascript development, but thought this was worth posting for those of you that do a lot of Windows Development and are wondering how to show a MessageBox in Silverlight. For those of you that have tried it:

MessageBox.Show("Hello world!");

OOPS! Compiler error... that doesn't work, Silverlight does not have a MessageBox class like WPF / WinForms / Win32. Instead, you can ask the browser to do this for you. How do you do this you might ask?

HtmlWindow.Alert("Hello world!");

This is the exact equivalent of the javascript alert function, which would look something like this:

alert("Hello world!");

So what if you want more control? Well, you will find the browser does not provide quite as much as desktop apps for this. In WPF, you can control the message, the title, the icon, the colours, buttons and more! Alert() will simply display a normal dialog with an OK button and the message, and a browser dependent title. The other option the browser gives you is to display a message box with "OK" and "Cancel" options and to be able to read the result of what the user chooses. In WPF you would do:

DialogResult result = MessageBox.Show("Shall I proceed?", "Title", MessageBoxButtons.OKCancel);
if (result == MessageBoxResult.OK)
{
  // process the OK
}

In Silverlight, the equivalent is:

bool result = HtmlPage.Window.Confirm("Shall I proceed?");
if (result)
{
  // process the OK
}

Tuesday 17 June 2008

Silverlight 2.0 Beta 2 - Creating a user control to be used as a base class

Little tip here that I worked out whilst trying to get the ShellBase class from Silverstone working in the XAML editor and Expression blend.

I started off with an abstract class which derived from UserControl, like follows:

    public abstract class ShellBase : UserControl, IShell

    {

        //... some code

    }

Unfortunately, neither Expression Blend nor Visual Studio's Cider designer likes this, they need to create an instance of the base class for some reason. You get an error message saying it couldn't create an instance of it. Removing the abstract constraint solves this (though violates OO, but I don't mind in this instance!).

Now I have some XAML which looks like this for defining my actual Shell:

<Silverstone:ShellBase x:Class="Silversocial.Client.Views.Shell"

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

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

   xmlns:Silverstone="clr-namespace:Silverstone;assembly=Silverstone">

    <Grid x:Name="LayoutRoot" Background="Black">

 

    </Grid>

</Silverstone:ShellBase>

VS and blend now complain because ShellBase does allow content to be added. The solution I discovered was fairly simple and was twofold:

1. Add a property called Content which shadows the UserControl's Content property and redirects to it

2. Add a ContentProperty attribute to the ShellBase which points to the Content property

    [ContentProperty("Content")]

    public class ShellBase : UserControl, IShell

    {

        /// <summary>

        ///    Redefine the base class's content property to keep the designers happy

        /// </summary>

        public new UIElement Content

        {

            get { return base.Content; }

            set { base.Content = value; }

        }

And that's it! Designer support enabled!

Hope this helps...

Neil

Update - 20/06/2008

It appears I was wrong about the ContentProperty attribute, it doesn't work. See this post for more info

Sunday 15 June 2008

Silverstone updated for SL 2.0 Beta 2

Just a quick note to inform that the Silverstone project has been updated for Silverlight 2.0 Beta 2. Get it here

Monday 19 May 2008

MVC Architecting Silverlight Applications Part 3 - Testing the ViewModel

In Part 2 of this series, I built a small class used to model our Login page - LoginViewModel.

In this post, I will demonstrate how to unit test this class to show that it behaves as expected. This is pretty essential as we want to be sure the class works properly before handing it over to our designer to build a view for!

I will be using TestDriven.NET's new Silverlight unit testing support which I blogged about earlier. This is unbelievably simple - just download and install the project template and then create a new Silveright NUnit Project called Silversocial.Client.Modules.Test

Building some test doubles


Before we can start unit testing our LoginViewModel, we need to fake out the dependencies. Given that there currently exists no mocking framework for Silverlight ( are you listening Ayende? ;-> ) we will manually build some stubs for our dependencies and then reuse them in our tests.

It is quite easy to way manually to build reusable stubs for an interface of your choosing. I simply follow these rules:
  • Use "explicit interface implementations" for all members

  • Implement properties as normal properties with a backing field (or as automatic properties if you'd prefer)

  • Implement methods by delegating the entire method body to a public event handler with the same signature and name as the method. Set the event handler to empty delegate to avoid null checks

  • Implement events by delegating the add/remove to a public event handler with the same signature as the event. Set the event handler to empty delegate to avoid null checks


Here is the code for the stub for the IAppShell interface.

using Silverstone;

 

namespace Silversocial.Client.Modules.Tests.Stubs

{

    public class AppShellStub : IAppShell

    {

        private User user;

        private IView view;

 

        public User User

        {

            get { return this.user; }

        }

 

        public IView View

        {

            get { return this.view; }

        }

 

        User IAppShell.User

        {

            get { return this.user; }

            set { this.user = value; }

        }

 

        void IShell.SetView(IView view)

        {

            this.view = view;

        }

    }

}


And now the stub for the ILoginDataProvider, also following the guidelines set above:

using System;

 

namespace Silversocial.Client.Modules.Tests.Stubs

{

    public class LoginDataProviderStub : ILoginDataProvider

    {

        private EventHandler<ValidateUserCompletedEventArgs> validateUserCompleted = delegate { };

 

        public Action<User> ValidateUser = delegate { };

 

        public void RaiseValidateUserCompleted(ValidateUserCompletedEventArgs args)

        {

            this.validateUserCompleted(this, args);

        }

 

        event EventHandler<ValidateUserCompletedEventArgs> ILoginDataProvider.ValidateUserCompleted

        {

            add { this.validateUserCompleted += value; }

            remove { this.validateUserCompleted -= value; }

        }

 

        void ILoginDataProvider.ValidateUser(User user)

        {

            this.ValidateUser(user);

        }

    }

}


We will create a "ViewStubBase" which implements the IView interface itself. This will form the base class for all other stubs of the views.

using System;

using Silverstone;

 

namespace Silversocial.Client.Modules.Tests.Stubs

{

    public abstract class ViewStubBase : IView

    {

        public Action OnLoad = delegate { };

        public Action OnUnload = delegate { };

 

        void IView.OnLoad()

        {

            this.OnLoad();

        }

 

        void IView.OnUnload()

        {

            this.OnLoad();

        }

    }

}


And now the stub for the ILoginView interface. As you can see we just implement the LoginUnsuccessful method and call a public event handler which does nothing by default. The allows the test to listen to the method being called if it wants to, and can for example validate if it is called or not.

using System;

 

namespace Silversocial.Client.Modules.Tests.Stubs

{

    public class LoginViewStub : ViewStubBase, ILoginView

    {

        public Action LoginUnsuccessful = delegate { };

 

        void ILoginView.LoginUnsuccessful()

        {

            this.LoginUnsuccessful();

        }

    }

}


The other views are just empty classes for now. The first:

namespace Silversocial.Client.Modules.Tests.Stubs

{

    public class FriendListStub : ViewStubBase, IFriendListView

    {

    }

}


And the other...

namespace Silversocial.Client.Modules.Tests.Stubs

{

    public class RegisterStub : ViewStubBase, IRegisterView

    {

    }

}


The test fixture



Finally it's time to implement the test fixture, just using the standard NUnit syntax for defining the tests and setup method. The SetUp creates all the stubs, so they can be used by each test.

Note I am using the "AAA" pattern which was recently coined by Ayende for RhinoMocks 3.5 - I really like it! This is the way I have written most of my tests in the past, and it's nice to have a formal name for the stages undergone (especially when it's an alliterism)

Here are the tests:

using NUnit.Framework;

using Silversocial.Client.Modules.Tests.Stubs;

using Silverstone;

 

namespace Silversocial.Client.Modules.Tests

{

    [TestFixture]

    public class LoginViewModelTester

    {

        private LoginViewStub loginViewStub;

        private AppShellStub shellStub;

        private FriendListStub friendListStub;

        private RegisterStub registerStub;

        private LoginDataProviderStub dataProviderStub;

        private LoginViewModel viewModel;

 

        [SetUp]

        public void SetUp()

        {

            this.shellStub = new AppShellStub();

            this.friendListStub = new FriendListStub();

            this.registerStub = new RegisterStub();

            this.dataProviderStub = new LoginDataProviderStub();

            this.viewModel = new LoginViewModel(shellStub, dataProviderStub, friendListStub, registerStub);

 

            this.loginViewStub = new LoginViewStub();

            ((IViewModel) this.viewModel).SetView(this.loginViewStub);

        }

 

        [Test]

        public void Login_WithoutUsernameAndPassword_CannotExecute()

        {

            Assert.IsFalse(this.viewModel.Login.CanExecute(null));

        }

 

        [Test]

        public void Login_WithUsernameAndPassword_CanExecute()

        {

            // Arrange

            this.viewModel.User.Username = "abc";

            this.viewModel.User.Password = "abc";

 

            // Assert

            Assert.IsTrue(this.viewModel.Login.CanExecute(null));

        }

 

        [Test]

        public void Login_BeforeCompleted_IsLoggingInIsTrue()

        {

            // Act

            this.viewModel.Login.Execute(null);

 

            // Assert

            Assert.IsTrue(this.viewModel.IsLoggingIn);

        }

 

        [Test]

        public void Login_AfterCompleted_IsLoggingInIsFalse()

        {

            // Act

            this.viewModel.Login.Execute(null);

            this.dataProviderStub.RaiseValidateUserCompleted(new ValidateUserCompletedEventArgs(false));

 

            // Assert

            Assert.IsFalse(this.viewModel.IsLoggingIn);

        }

 

        [Test]

        public void Login_AfterCompleted_RaisesCanExecuteChangedEvent()

        {

            // Arrange

            bool canExecuteChangedCalled = false;

            this.viewModel.Login.CanExecuteChanged +=

                delegate { canExecuteChangedCalled = true; };

 

            // Act

            this.dataProviderStub.RaiseValidateUserCompleted(new ValidateUserCompletedEventArgs(false));

 

            // Assert

            Assert.IsTrue(canExecuteChangedCalled);

        }

 

        [Test]

        public void Login_WhilstLoggingIn_CannotExecute()

        {

            // Arrange

            this.viewModel.User.Username = "abc";

            this.viewModel.User.Password = "abc";

            this.viewModel.IsLoggingIn = true;

 

            // Assert

            Assert.IsFalse(this.viewModel.Login.CanExecute(null));

        }

 

        [Test]

        public void Login_Always_CallsValidateUserOnDataProvider_WithCorrectUser()

        {

            // Arrange

            User userSentToDataProvider = null;

            this.dataProviderStub.ValidateUser +=

                u => userSentToDataProvider = u;

 

            // Act

            this.viewModel.Login.Execute(null);

 

            // Assert

            Assert.AreEqual(this.viewModel.User, userSentToDataProvider);

        }

 

        [Test]

        public void Login_WithInvalidDetails_CallsLoginUnsuccessfulOnView()

        {

            // Arrange

            this.dataProviderStub.ValidateUser +=

                u => this.dataProviderStub.RaiseValidateUserCompleted(new ValidateUserCompletedEventArgs(false));

            bool loginUnsuccessfulCalledOnView = false;

            this.loginViewStub.LoginUnsuccessful +=

                () => loginUnsuccessfulCalledOnView = true;

 

            // Act

            this.viewModel.Login.Execute(null);

 

            // Assert

            Assert.IsTrue(loginUnsuccessfulCalledOnView);

        }

 

        [Test]

        public void Login_WithValidDetails_SetsFriendListViewOnShell()

        {

            // Arrange

            this.dataProviderStub.ValidateUser +=

                u => this.dataProviderStub.RaiseValidateUserCompleted(new ValidateUserCompletedEventArgs(true));

 

            // Act

            this.viewModel.Login.Execute(null);

 

            // Assert

            Assert.AreEqual(this.friendListStub, this.shellStub.View);

        }

 

        [Test]

        public void Login_WithValidDetails_SetsUserOnShell()

        {

            // Arrange

            this.dataProviderStub.ValidateUser +=

                u => this.dataProviderStub.RaiseValidateUserCompleted(new ValidateUserCompletedEventArgs(true));

 

            // Act

            this.viewModel.Login.Execute(null);

 

            // Assert

            Assert.AreEqual(this.viewModel.User, this.shellStub.User);

        }

 

        [Test]

        public void Register_Always_SetsRegisterViewOnShell()

        {

            // Act

            this.viewModel.Register.Execute(null);

 

            // Assert

            Assert.AreEqual(this.registerStub, this.shellStub.View);           

        }

    }

}


And here you can see them running in the Resharper test runner - they all pass!



Now I can confidently pass my ViewModel to my designer to build a view against...

Or can I? Without a data provider, he's going to have problems creating and testing his view. This will be the subject of the next post.

Sunday 18 May 2008

MVC Architecting Silverlight Applications Part 2 - Building a ViewModel

In Part 1 of this series I talked about and described the Model-View-ViewModel (MVVM) pattern.

In this post I will describe the application I wish to build to demonstrate this pattern to you, and at the same time demonstrate usage of the Silverstone framework.

A "social networking" application


In picking my sample app I wanted to choose something fairly simple. I decided on a small social networking app, which would basically allow the following use cases:
  1. Register - A user can enter their email address and choose a password. The user must confirm their password. Password must be between 4 and 10 characters. After registering, the user proceeds to use case 3

  2. Login - An existing user can enter their email address and password to login. If they enter the wrong details the system should inform them that their details were incorrect. After logging in, the user proceeds to use case 3

  3. View Friends - Displays a list of friends for the currently logged in user.
And that's it! Despite being fairly minimal (and not that useful without being able to add friends or contact them!) that's all I am going to build for now I think.

Creating a solution


We will name this application "Silversocial" (not very imaginative I know, but it's only a demo app!)

You will require Visual Studio 2008, the Silverlight Tools for Visual Studio, and a copy of Silverstone.dll.

Start off by creating a new project of type Silverlight Application named Silversocial.Client.Views. Choose to create a new solution and call it Silversocial



Choose to add a new Web to the solution for hosting the Silverlight content, and call it Silversocial_WebHost (I choose a web application because I prefer them). The solution will be created containing a Silverlight project and a Web application project.



Out of interest, if you right click on the Web Application project properties, you will see a new tab called "Silverlight links" and you will see that the Silverlight application you just created has been added for you automatically. All this really means is that when you build the Silverlight application, the compiled .xap file will be copied into the Web application's /ClientBin folder.



The shell


The shell in a Silverstone application is the central view component which is responsible for managing the other views in the application. Hence, the IShell interface contains just one method:

void SetView(IView view)

Typically an application will implement the shell as the main UI component containing any navigation and common elements for every page (much like ASP.NET's master page). The application will create its own derived IShell interface and expose any elements required by the individual pages through that interface.

So, given the requirements specified earlier, our application's shell only requires an extra property - the currently logged in User. This would allow the shell's view to display the user and allow the other pages to retrieve it when necessary.

To begin, we will create another Silverlight class project called Silversocial.Client.Modules to house the rest of our application's interfaces and concrete implementations. Obviously in a larger application you would consider splitting your code into multiple assemblies grouped by role.

First, the User class which stores the username and password:

using System.ComponentModel;

 

namespace Silversocial.Client.Modules

{

    public class User : INotifyPropertyChanged

    {

        private string username;

        private string password;

 

        public event PropertyChangedEventHandler PropertyChanged = (s,p) => {};

 

        public string Username

        {

            get { return this.username; }

            set

            {

                this.username = value;

                this.PropertyChanged(this, new PropertyChangedEventArgs("Username"));

            }

        }

 

        public string Password

        {

            get { return this.password; }

            set

            {

                this.password = value;

                this.PropertyChanged(this, new PropertyChangedEventArgs("Password"));

            }

        }

    }

}


And now the shell interface itself:

using Silverstone;

 

namespace Silversocial.Client.Modules

{

    public interface IAppShell : IShell

    {

        User User { get; set; }

    }

}


Creating the first ViewModel


For now, we will not worry about building a concrete View. Instead, we will start with our ViewModel. The page we will build is the Login page, and we will create a new class called LoginViewModel for it.

ILoginView will be the interface which our View will have to implement, and has a single method as follows:

using Silverstone;

 

namespace Silversocial.Client.ViewModels

{

    public interface ILoginView : IView

    {

        void LoginUnsuccessful();

    }

}


The contract states that the LoginUnsuccessful() method will be called by the ViewModel if the login is unsuccessful.

On the other side of the equation, our ViewModel will require some way of actually validating the user. In the real world application we will expose a service for doing this, but for now, let's stub it out with the following interface:

using System;

 

namespace Silversocial.Client.Modules

{

    public class ValidateUserCompletedEventArgs : EventArgs

    {

        public ValidateUserCompletedEventArgs(bool successful)

        {

            this.Successful = successful;

        }

 

        public bool Successful { get; set; }

    }

 

    public interface ILoginDataProvider

    {

        event EventHandler<ValidateUserCompletedEventArgs> ValidateUserCompleted;

        void ValidateUser(User user);

    }

}


(Note that this interface is implementing an asynchronous pattern - raising the ValidateUserCompleted event when the method has completed. This ties in well with the fact that Ajax requests are asynchronous, and that Silverlight's WCF ChannelFactory implementation only supports asynchronous requests.)

The View Model is shown below. The main features are:
  • All dependencies passed through as interfaces to the constructor. This includes other views, the data provider, and the shell.

  • Property exposed for the User, which the View can bind to.

  • Property exposed for whether we are in the middle of a login attempt, which the View can bind to.

  • Exposes a Login command which will attempt to use the data provider to validate the user. If successful the callback will set the user on the shell and change to the FriendListView. If unsuccessful the callback will call the LoginUnsuccessful() method on the view.

  • Exposes a Register command which will simply change views to the RegisterView.

using Silverstone;

 

namespace Silversocial.Client.Modules

{

    /// <summary>

    ///    ViewModel for the login page

    /// </summary>

    public class LoginViewModel : ViewModelBase<ILoginView>

    {

        // Dependencies

        private readonly IAppShell shell;

        private readonly ILoginDataProvider dataProvider;

        private readonly IFriendListView friendListView; // This is just an empty view interface for now

        private readonly IRegisterView registerView; // This is just an empty view interface for now

 

        // Commands

        private readonly ICommand login;

        private readonly ICommand register;

 

        // Data Fields

        private readonly User user = new User();

        private bool isLoggingIn;

 

        public LoginViewModel(IAppShell shell, ILoginDataProvider dataProvider, IFriendListView gameChooserView, IRegisterView registerView)

        {

            this.shell = shell;

            this.registerView = registerView;

            this.friendListView = gameChooserView;

            this.dataProvider = dataProvider;

            this.login = new LoginCommand(this);

            this.register = new RegisterCommand(this);

        }

 

        /// <summary>

        ///    Gets the user being logged in

        /// </summary>

        public User User

        {

            get { return this.user; }

        }

 

        /// <summary>

        ///    Gets or sets whether the user is currently being logged in

        /// </summary>

        public bool IsLoggingIn

        {

            get { return isLoggingIn; }

            set

            {

                isLoggingIn = value;

                this.RaisePropertyChanged("IsLoggingIn");

            }

        }

 

        /// <summary>

        ///    Gets the command used to login the user

        /// </summary>

        public ICommand Login

        {

            get { return this.login; }

        }

 

        /// <summary>

        ///    Gets the command used to register a new user

        /// </summary>

        public ICommand Register

        {

            get { return register; }

        }

 

        private class LoginCommand : CommandBase<LoginViewModel>

        {

            public LoginCommand(LoginViewModel viewModel) : base(viewModel)

            {

                this.ViewModel.dataProvider.ValidateUserCompleted += this.HandleValidateUserCompleted;

            }

 

            public override bool CanExecute(object parameter)

            {

                // Used to inform the command framework that we can only login once the user

                // has entered a username and password and we are not already in the middle of a login

                return !string.IsNullOrEmpty(this.ViewModel.User.Username)

                    && !string.IsNullOrEmpty(this.ViewModel.User.Password)

                    && !this.ViewModel.IsLoggingIn;

            }

 

            public override void Execute(object parameter)

            {

                // Call the Async method on the data provider to validate the user.  The ViewModel will

                // handle the response to this method

                this.ViewModel.dataProvider.ValidateUser(this.ViewModel.User);

 

                // Record that we are currently in the middle of a login attempt

                this.ViewModel.IsLoggingIn = true;

            }

 

            private void HandleValidateUserCompleted(object sender, ValidateUserCompletedEventArgs e)

            {

                // Record that we have finished attempting to log in

                this.ViewModel.IsLoggingIn = false;

 

                if (e.Successful)

                {

                    this.ViewModel.shell.User = this.ViewModel.User;

                    this.ViewModel.shell.SetView(this.ViewModel.friendListView);

                }

                else

                {

                    this.ViewModel.View.LoginUnsuccessful();

                }

 

                // Raise the "CanExecuteChanged" method

                this.RaiseCanExecuteChanged();

            }

 

        }

 

        private class RegisterCommand : CommandBase<LoginViewModel>

        {

            public RegisterCommand(LoginViewModel viewModel) : base(viewModel)

            {

            }

 

            public override void Execute(object parameter)

            {

                // Simply use the shell to navigate to the register view when this command is executed

                this.ViewModel.shell.SetView(this.ViewModel.registerView);

            }

        }

    }

}

The next post

In the next post I will talk about unit testing the view model, and will start to wire things together so our designer can build a View for all this.