Friday, 29 October 2010

MVVM – Is it Worth the Pain?

After finding it very easy to get MVVM working in WPF with IronPython, I thought it would be trivial to achieve the same thing in Silverlight. Unfortunately, my bindings didn’t work at all after porting a simple game to Silverlight. The problem may have something to do with the issues described in this blog post, but since I needed to demo my code for a local user group event, I abandoned MVVM and went back to just talking directly to the controls from within my ViewModel, which worked perfectly, and simplified my code considerably. It made me wonder why I was using MVVM in the first place.

The Pain of MVVM

I jumped on the bandwagon fairly early and have been writing the majority of my WPF and Silverlight code using MVVM. But to be honest, it has not been plain sailing. There is a real elegance to it that I like, and I love the testability, but there have been plenty of pain points.

For example, triggering animations and discovering when they have finished from the ViewModel has been a nightmare. I’ve tried various solutions, finding one that works with Silverlight and one with WPF but none that work with both, and have managed to crash Visual Studio dozens of times in the process.

Even simple things like setting the focus to the appropriate controls requires a rather convoluted system of “behaviours”, to do something that is a single line of code with access to the controls themselves. And every time I create a behaviour I seem to spend ages debugging my dependency properties, trying to work out why they aren’t doing what I expected.

The Purpose of MVVM

So if MVVM is so painful for non-trivial applications, why use it at all? What’s the point of MVVM? I think there are three answers.

1. Testability

The first driver for using MVVM is testability. If we put our logic in the C# “code-behind” of a XAML class, then running unit tests on that logic becomes very difficult. But with IronPython, that consideration is irrelevant. Since it is a dynamic language, and we are not using “code-behind” in any case, my non-MVVM version of my ViewModel is just as testable as the one that used data binding exclusively.

2. Data Binding

The second motivation for using MVVM is that the pattern encourages the use of data binding, and simplifies it considerably by removing the need for data converters or complicated binding expressions. But why is data-binding to a TextBox better than just getting or setting its Text property?

One of the key benefits of data-binding comes when we want to bind the same thing to more than one property. A Command object is a good example. One Command object could be bound to a drop-down menu and a toolbar button. So setting the Command’s IsEnabled state can be used to enable and disable both views. But most of the time, binding is a one-to-one relationship.

Data binding also saves a bunch of code in CRUD type applications where you are binding directly to properties on an existing model type, but I don’t tend to write applications like that anyway. I think you can use it to make magical things happen with input validation too, but again, it’s not something I’ve ever needed.

3. Designability

The third driver behind MVVM is the goal of designer / developer separation. The idea is that a designer can create a XAML file and bind it to test data, and then the developer can come along and create the real DataContext at a later date. The idea certainly sound impressive, but I can’t help but think that the designer will run into all the problems mentioned above if he actually wants to give his XAML GUI a real workout. And the truth is that I’ve never worked with a designer writing XAML and will not be doing so in the foreseeable future. The graphic designers we use send us bitmaps and Flash mockups.

A Hybrid Approach

I am now wondering whether I should think of my ViewModel more as a “Presenter”. It could still be the DataContext of the object defined in XAML to enable data-binding where required, but it would also have access directly to any properties on that XAML object. For testability in statically typed languages, you could define an interface with methods like StartAnimation or SetFocusToTextBox – a little cumbersome perhaps, but probably no more so than the hoops you have to jump through to make these things happen from your ViewModel using nothing but data binding.

Anyway, looks like I’m not alone in questioning MVVM. Here’s a good post from K Scott Allen. What do you think? Does MVVM fail a cost-benefit analysis for the types of application you work on?

Thursday, 28 October 2010

Creating Silverlight Apps with IronPython

Using IronPython to create Silverlight applications is a little different from using C#. With C# you are building a .xap file, which contains all the compiled code for your application. However, in IronPython, the recommended way is not to create a .xap file at all. Instead you simply write Python script in your HTML page, or in .py files hosted on your web server.

Getting Started

The easiest way to get started is by using the latest IronPython (currently 2.7 beta 1) which comes with Visual Studio 2010 integration. This enables you to simply create a new “IronPython Silverlight Web Page” project. However, don’t worry if you don’t have or want to use VS2010 – the process is almost the same without it.

When you create your new Silverlight project, it creates two files for you. The first is a simple HTML page:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <script type="text/javascript">
        window.DLR = { settings: { console: true } }
    </script>
    <script src="http://gestalt.ironpython.net/dlr-latest.js" type="text/javascript"></script>
    <title>SilverlightPage1</title>
</head>
<body>
    <input id="Button1" type="button" value="Say, Hello!" />
    <script type="text/python" src="SilverlightPage1.py"></script>
</body>
</html>

Including the DLR

There are a few interesting points of note in the <head> section of this page. First is the dlr-latest.js script file. This is all that is needed to enable python (and xaml) scripting directly in HTML. The settings: { console: true } section enables a very cool debugging feature in your web page, whereby you get an IronPython interactive interpreter that you can pop up from the bottom of your web page:

IronPython Interactive Interpreter

Running a .py Script

Then we have the Python script itself. The project template includes a Python file containing some basic code to subscribe to the button onclick event and show an alert.

def SayHello(s,e):
    window.Alert("Hello, World!")
document.Button1.events.onclick += SayHello

Embedding Python in the HTML

There is in fact no need for our Python script to be in a .py file if we don’t want to. We can put Python code directly in the HTML inside a <script> block if we want:

<body>
    <input id="Button1" type="button" value="Say, Hello!" />
    <script type="text/python">
    def SayHello(s,e):
        window.Alert("Hello from HTML")
 
    document.Button1.events.onclick += SayHello
    </script>
</body>

Running the Page

When you run the page from Visual Studio, it starts the “Chiron Development Server” to host your page. You don’t need this to develop for IronPython, but one thing I discovered is that you do need the MIME type to be set up correctly for .py files. For example, if you are using WebMatrix you need to put a web.config file in your application root folder with the following content:

<configuration>
    <system.webServer>
        <staticContent>
            <mimeMap fileExtension=".py" mimeType="text/python" />
        </staticContent>
    </system.webServer>
</configuration>

Sadly I couldn’t work out a way of getting Visual Studio to break on specific lines of Python script despite trying attaching to Chiron and to my Web Browser. I guess it may be possible to step through the script with a debugger for the browser, but I haven’t tried that yet.

Using XAML

Obviously XAML is very important for Silverlight applications and it is very easy to use with the DLR. We can start by adding a simple XAML file to our project. Annoyingly, the Visual Studio add item dialog filters out all the templates except the IronPython ones. Hopefully that will be fixed in a future release.

We’ll create a MainForm.xaml file with the following basic content:

<UserControl 
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <StackPanel Background="BurlyWood">
        <TextBlock Margin="5" Text="Enter your name:"/>
        <TextBox Margin="5" x:Name="textBoxName"/>
        <Button Margin="5" x:Name="buttonOK" Content="OK" />
    </StackPanel>
</UserControl>

Now in our HTML page, all that is needed is to specify the XAML and the size of the Silverlight object that will host it:

<script id="MainForm" type="application/xml+xaml" width="200" height="100" src="MainForm.xaml"></script>

As before, there is no need for the XAML to be in a separate file. We can put it directly within the script block if needed. Here’s our app running:

IronPython Silverlight App

Now suppose we want to write some Python code to run when the OK button is clicked instead of the “Say, Hello!” button. We can use Python script in the way already shown, but need to mark the <script> tag with class=”MainForm” in order to ensure that it runs against the correct Silverlight object that contains our MainForm UserControl. This is because the DLR supports multiple Silverlight controls on your page at a time, and by default will create a new one for each xaml script. The xaml variable is pre-loaded with the root element of the loaded xaml – in our case, a UserControl.

<script class="MainForm" type="text/python">
def SayHello(s,e):
    window.Alert("Hello " + xaml.textBoxName.Text)

xaml.buttonOK.Click += SayHello
</script>

Now when we run this, it works (sort of). In FireFox, the alert appears but you have to wait several minutes before it lets you click on it. I have no idea why. IE8 works OK so long as you are running against the latest gestalt (otherwise the xaml is None so the subscription to the button click event fails).

Going Further

Obviously this only covers the absolute basics. Visit http://www.ironpython.net/ironpython/browser/ for more documentation and instructions. I may blog a bit more on this at a later date.

Wednesday, 27 October 2010

IronPython 2.7 Visual Studio Integration

I’ve been trying out IronPython 2.7 beta 1, which includes Visual Studio 2010 integration and I’ve been very impressed. Here’s a brief rundown of the features (at least the ones I’ve found).

Project Templates

Four new project templates are included – these are a Console Application, a WinForms application, a WPF application and finally a Silverlight web page. The templates each have just enough code to get you started.

Project Templates

The Code Editor

As you might expect there is syntax highlighting for Python files:

Syntax Highlighting

Another nice touch is that pressing backspace with the cursor at the start of a line of code moves it in one level of indentation. What I wasn’t expecting was intellisense, but it’s available in some places (though not everywhere since the dynamic nature of Python means you can’t guarantee that a variable will keep the same type that it was initially assigned).

Intellisense

Another nice touch is red squiggly lines indicating syntax errors – very useful if like me you keep forgetting the colon at the end of if statements:

Syntax Errors

Also the Navigation Bar is populated with the classes and methods in your source file:

Navigation Bar

Another very nice touch is that the Find All References and Go To Definition both work. Also the Object Browser includes classes and methods from your IronPython source files.

Solutions

When you create an IronPython project it creates a regular .sln file, but your project is a .pyproj file (which like .csproj is an msbuild project file under the hood). It doesn’t have too many configuration options, but it does allow you to add search paths for external python scripts or .NET libraries. You can also specify which your startup file is.

Startup File

Search Path can also be configured in the Solution Explorer:

Search Path

The Debugger

One of the most compelling reasons to use Visual Studio to write your IronPython apps is support for the debugger. You can set breakpoints and step through your code:

Breakpoints

Sadly tooltips showing the values of variables don’t seem to be implemented. The only tooltips I could get up was by hovering over the open quotes of a string literal. Also you can’t get at variable contents using the Immediate or Watch windows. Neither can you use Python variables or expressions for breakpoint conditions.

Watch window

However, the Locals window does come to the rescue and can be used to examine the contents of variables while you are at a breakpoint.

Locals Window

The IronPython Interactive Window

Another great feature is the IronPython Interactive Window. This is the same old familiar interactive IronPython interpreter you get when you type ipy.exe, except that it has a few tricks up its sleeve. It supports both syntax highlighting and intellisense, which works even better here since it can look at the live objects rather than having to analyse your source code.

IronPython Interactive Window

There is an option on the debug menu to execute your application in IronPython Interactive:

Execute Project in IronPython Interactive

This brings up the IronPython interactive window and attempts to run your project in it. You can even change scope, and investigate the value of variables in the various scopes of the different modules of your application. Here’s it running the simple test app I showed earlier:

IronPython Interactive

There are still a couple of issues using this for debugging. First, it doesn’t apply the Search Path to the interactive session so import statements fail. Second, running in this mode doesn’t seem to invoke the debugger, so you won’t stop at breakpoints. Hopefully these issues will be addressed in a future update of the tools.

Another nice feature is the ability to select IronPython code in the editor, right-click it and say – Send to Interactive. You need to be on a blank line in the interactive console though or it can get a bit confused. But this is a great way to get longer functions into the interactive window.

Send to Interactive

Conclusion

The Visual Studio support for IronPython is very impressive. It still needs a few enhancements, particularly in the area of debugging, but there are still plenty of advantages to using Visual Studio for IronPython development over simply working directly with files.

Since this post is fairly long, I’ll save comments on Silverlight with IronPython for another time.

Tuesday, 26 October 2010

Change to Solution Folder in Package Manager Console

When you install nupack (which seems likely to be renamed nuget in the near future), you get a new dockable Visual Studio 2010 window called the Package Manager Console which allows you to run nupack commands right from within VS2010.

nuget-console

The great thing about this window is that it can be used for more than just nupack commands. It is a fully working PowerShell window and all the commands on your path are also available. For example, I use Mercurial on a number of my applications, so it allows me to input commands such as hg add or hg commit directly within the console window.

There was just one slight snag, and that is that the current working directory of the Package Manager Console seems to default to your user account:

PM> pwd
Path
----
C:\Users\Mark

So, despite knowing virtually nothing about PowerShell, I set about working out how I could automate this process. The first thing I discovered was that you can query PowerShell for all the variables that are available using the Get-Variable command. This will show the names and current values of all variables.

Sadly, there seemed to be none containing the path of the loaded solution, but asking a question on StackOverflow pointed me in the right direction. There is a variable called $dte which is a COM object allowing automation of the VS development environment. We can ask this for the path of the loaded solution:

PM> $dte.Solution.FileName
C:\Users\Mark\Code\TestApp\TestApp.sln

We now need to find a way to strip off the filename to get the folder. You can list all available PowerShell commands with by typing Get-Command. Eventually after some searching on Google I found a way to strip the filename off this path:

PM> Split-Path -parent $dte.Solution.FileName
C:\Users\Mark\Code\TestApp

To change to this folder you take this string and pipe it into the cd command as follows:

PM> Split-Path -parent $dte.Solution.FileName | cd
PM> pwd

Path
----
C:\Users\Mark\Code\TestApp

Mission almost accomplished, but that is a rather cumbersome command to remember. I wanted to make a PowerShell command immediately available to me. This requires editing my PowerShell user profile. The path to this is found in the $profile variable:

PM> $profile
C:\Users\Mark\Documents\WindowsPowerShell\NuPack_profile.ps1

This file didn’t actually exist (nor did the WindowsPowerShell folder), so I had to create a blank one. Then, I added my snippet of script into a function:

nuget-powershell

Having done that, you need to reload Visual Studio, and after loading a solution, you can type solutionFolder to navigate to the solution folder:

PM> solutionFolder
PM> pwd

Path
----
C:\Users\Mark\Code\TestApp

And that's it. Now I can run my Mercurial commands from within the Package Manager Console:

PM> hg status
M UnitTests\UnitTests.csproj
? UnitTests\Thread.cs

Saturday, 9 October 2010

WPF Collision Detection with Canvas and ScaleTransform

As part of my continuing exercise learning IronPython, I ported an old Windows Forms game I had up on CodePlex to WPF. The game is called Asterisk, and was a favourite of mine when I was about 8 years old on the BBC Micro. The objective is simply to avoid the stars and get through the gap on the right hand side. The only control is to hold down a key to make the line go up instead of down.

Here’s what the current WPF version looks like:

WPF Asterisk

One of the challenges was implementing collision detection. I needed to check if the current point intersected with a star or not. I initially hoped I could use Andy Beaulieu’s Silverlight collision detection code, but sadly that uses VisualTreeHelper.FindElementsInHostCoordinates, which isn’t available in WPF.

However, a solution was readily at hand with VisualTreeHelper.HitTest. I rather stupidly failed to notice that there was a much simpler overload than the first search result on MSDN, so my initial Python code was over-complicated:

def CheckCollisionPoint(point, control):
    hits = []
    def callbackFunc(hit):
        hits.append(hit.VisualHit)
        return HitTestResultBehavior.Stop
    callback = HitTestResultCallback(callbackFunc)
    VisualTreeHelper.HitTest(control, None, callback,
        PointHitTestParameters(point))    
    return len(hits) > 0

Using a more appropriate HitTest overload simplifies things greatly:

def CheckCollisionPoint(point, control):
    hit = VisualTreeHelper.HitTest(control, point)
    return hit != None

However, there were still two difficulties. First was that point was coordinates relative to the canvas, whilst the control was a star object placed onto that canvas. This was simple enough to fix – I just needed to offset the coordinates by the Canvas.Top and Canvas.Left attached properties of the star.

However, problems came when I attempted to change the size of the stars with a scale transform:

<Path xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  Stroke="White" 
  StrokeThickness="2" 
  StrokeStartLineCap="Round" 
  StrokeEndLineCap="Round" 
  StrokeLineJoin="Round" 
  Data="M 0,0 l 5,0 l 2.5,-5 l 2.5,5 l 5,0 l -3.5,5 l 1,5 l -5,-2.5 l -5,2.5 l 1,-5 Z">
  <Path.RenderTransform>
    <ScaleTransform ScaleX="0.8" ScaleY="0.8" />
  </Path.RenderTransform>
</Path>

This caused collision detection to break because HitTest does not take the RenderTransform into account. I initially fixed this by dividing the point coordinates by the scale factor from the XAML. However, I then came across this blog post which demonstrates a better approach that will cope with any kind of transforms, including rotations. You can get an inverse transform from the render transform, and apply that to your point. So the final version of my WPF hit-test function in IronPython is as follows:

def CheckCollisionPoint(point, control):
    transformPoint = control.RenderTransform.Inverse.Transform(point)
    hit = VisualTreeHelper.HitTest(control, transformPoint)
    return hit != None

If you have IronPython installed, download the code and try it yourself.

Wednesday, 6 October 2010

WPF and MVVM in IronPython

I’ve been getting to grips with IronPython recently, and wanted to see how easy it would be to use the MVVM pattern. What we need is a basic library of MVVM helper functions. First is a class to load an object from a XAML file.

import clr
clr.AddReference("PresentationFramework")
clr.AddReference("PresentationCore")

from System.IO import File
from System.Windows.Markup import XamlReader

class XamlLoader(object):
    def __init__(self, xamlPath):
        stream = File.OpenRead(xamlPath)
        self.Root = XamlReader.Load(stream)
        
    def __getattr__(self, item):
        """Maps values to attributes.
        Only called if there *isn't* an attribute with this name
        """
        return self.Root.FindName(item)

In addition to loading the XAML, I’ve added a helper method to make it easy to access any named items within your XAML file, just in case the MVVM approach is proving problematic and you decide to work directly with the controls.

Next we need a base class for our view models to inherit from, which implements INotifyPropertyChanged. I thought it might be tricky to inherit from .NET interfaces that contain events, but it turns out to be remarkably simple. We just inplement add_PropertyChanged and remove_PropertyChanged, and then we can raise notifications whenever we want.

from System.ComponentModel import INotifyPropertyChanged
from System.ComponentModel import PropertyChangedEventArgs

class ViewModelBase(INotifyPropertyChanged):
    def __init__(self):
        self.propertyChangedHandlers = []

    def RaisePropertyChanged(self, propertyName):
        args = PropertyChangedEventArgs(propertyName)
        for handler in self.propertyChangedHandlers:
            handler(self, args)
            
    def add_PropertyChanged(self, handler):
        self.propertyChangedHandlers.append(handler)
        
    def remove_PropertyChanged(self, handler):
        self.propertyChangedHandlers.remove(handler)

The next thing we need is a way of creating command objects. I created a very basic class that inherits from ICommand and allows us to run our own function when Execute is called. Obviously it could easily be enhanced to properly support CanExecuteChanged and command parameters.

from System.Windows.Input import ICommand

class Command(ICommand):
    def __init__(self, execute):
        self.execute = execute
    
    def Execute(self, parameter):
        self.execute()
        
    def add_CanExecuteChanged(self, handler):
        pass
    
    def remove_CanExecuteChanged(self, handler):
        pass

    def CanExecute(self, parameter):
        return True

And now we are ready to create our application. Here’s some basic XAML. I’ve only named the grid to demonstrate accessing members directly, but it obviously is not good MVVM practice.

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="IronPython MVVM Demo"
    Width="450"
    SizeToContent="Height">
    <Grid Margin="15" x:Name="grid1">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Label Grid.Row="0" Grid.Column="0" FontSize="24" Content="First Name:" />
        <Label Grid.Row="0" Grid.Column="1" FontSize="24" Content="{Binding FirstName}" />
        <Label Grid.Row="1" Grid.Column="0" FontSize="24" Content="Surname:" />
        <Label Grid.Row="1" Grid.Column="1" FontSize="24" Content="{Binding Surname}" />
        <Button Grid.Row="2" FontSize="24" Content="Change" Command="{Binding ChangeCommand}" />
    </Grid>
</Window>

Now we can make our ViewModel. It will have FirstName and Surname attributes as well as an instance of our Command object:

class ViewModel(ViewModelBase):
    def __init__(self):
        ViewModelBase.__init__(self)
        self.FirstName = "Joe"
        self.Surname = "Smith"
        self.ChangeCommand = Command(self.change)
    
    def change(self):
        self.FirstName = "Dave"
        self.Surname = "Brown"
        self.RaisePropertyChanged("FirstName")
        self.RaisePropertyChanged("Surname")

And finally we are ready to create our application. Simply load the XAML in with the XamlLoader and set the DataContext. I also demonstrate setting the background colour here, to show how easy it is to access named elements in the XAML:

from System.Windows import Application
from System.Windows.Media import Brushes

xaml = XamlLoader('WpfMvvmDemo.xaml')
xaml.Root.DataContext = ViewModel()
xaml.grid1.Background = Brushes.DarkSalmon
app = Application()
app.Run(xaml.Root)
Now we run it and see:

mvvm-python-1

And click the button to see:

mvvm-python-2

And that’s all there is to it. It may even be simpler than doing MVVM from C#.

Monday, 4 October 2010

Clipboard Access in IronPython

I’m slowly getting into the swing of using IronPython to write small scripts to help me do things quicker. I’ve been updating some of the old posts on this blog to use syntaxhighlighter which is a much cleaner solution than the old mechanism. However, it did require a little bit of text manipulation of each code sample before updating it on the blog. The code simply reads the code snippet out the clipboard, performs a few basic transforms and then copies the transformed code back to the clipboard.

import io
import clipboard
code = clipboard.getText()
brush = 'csharp' if not code[0] == '<' else 'xml'
substitutions = [('&','&amp;'),('<','&lt;'),('>','&gt;')]
for a,b in substitutions:
    code = code.replace(a,b)
print code
code = '<pre class="brush: %s">%s</pre>' % (brush, code)
clipboard.setText(code)

The clipboard module is my own very small wrapper, which makes use of the Clipboard object from System.Windows.Forms:

import clr
clr.AddReference('System.Windows.Forms')
from System.Windows.Forms import Clipboard

def setText(text):
    Clipboard.SetText(text)
    
def getText():
    return Clipboard.GetText()

Friday, 1 October 2010

Installing Windows Virtual PC on Windows 7 Home Premium

Microsoft have replaced Virtual PC 2007 with “Windows Virtual PC”, but theoretically it is only supported with Windows 7 Professional and above. However, if you head over to the Windows Virtual PC website, and say that you have Windows 7 Professional, it enables the downloads of Windows XP Mode and Windows Virtual PC. You only need to download the Virtual PC part, which arrives as the rather cryptically named Windows6.1-KB958559-x86.msu. Simply double-click to install.

Once installed you may, like me, run into the issue that hardware assisted virtualization is not enabled in your BIOS. I have a Dell laptop, and it was a matter of hitting F12 on bootup and searching around for the option in the BIOS settings. More info on enabling HAV.

The final step was to load up one of the old Virtual PC 2007 vmc files I had lying around. This went smoothly, although my virtualized XP did attempt and fail to install new device drivers when it booted up. Windows Virtual PC adds a Virtual Machines folder under your user account from which you can set up a new virtual machine if you require. I haven’t done this yet, but I might give it a go later and attempt to get Ubuntu running (something which was notoriously difficult under VPC 2007 so hopefully the process is a bit smoother now).

Anyway, it’s nice that Microsoft have made this tool available for free, which is very useful for software testing, and even better that its usable on Win 7 Home Premium, without having to upgrade to Professional.