A picture of me

Welcome, my name is Paul Stovell. I live in Brisbane and work on Octopus Deploy, an automated deployment tool for .NET applications.

Prior to founding Octopus Deploy, I worked for an investment bank in London building WPF applications, and before that I worked for Readify, an Australian .NET consulting firm. I also worked on a number of open source projects and was an active user group presenter. I was a Microsoft MVP for WPF from 2006 to 2013.

The absolute, #1 tool in every developer's D:\Tools directory should be Reflector. Reflector allows you to explore, disassemble and otherwise "research" .NET assemblies.

Lately I often find myself switching between multiple framework versions:

  • .NET 3.5 SP1
  • .NET 4.0
  • Silverlight 4.0

To switch between these frameworks, I use a little trick. I keep a Reflector.cfg file for each framework, and use a start menu shortcut to launch them:

My start menu, with three different Reflector shortcuts

Each shortcut points to a different .cfg file. The shortcut just needs to pass the /configuration variable to Reflector.exe:

D:\Tools\Reflector\Reflector.exe /configuration:"D:\Tools\Reflector\Configs\NET40.cfg"

Creating a configuration file is easy - just use the command above with a file that doesn't exist - for example:

Reflector.exe /configuration:"MyNewList.cfg"

You'll then be asked to populate the list:

Populating an assembly list

At this point, I like to drag in any extra assemblies I often use with that framework version:

  • For Silverlight, you can check under
    C:\Program Files (x86)\Microsoft SDKs\Silverlight\v3.0 C:\Program Files (x86)\Microsoft SDKs\Silverlight\v4.0
  • For WPF developers, try:
    C:\Windows\Microsoft.NET\Framework64\v4.0.30319\WPF

(If you don't have a 64-bit machine, change the paths appropriately)

Don't forget to also include other assemblies you often use, like:

  • Autofac DLL's
  • NHibernate DLL's
  • Enterprise library DLL's
  • Composite WPF DLL's
  • ASP.NET MVC DLL's
  • Magellan DLL's :)

Once you have all the assemblies you need, you can close Reflector - your list will be saved. You can re-open it again by creating a shortcut using the same .cfg file.

The final step is to mark the configuration file as read-only. I often open Reflector and drag in any crazy DLL I find during the course of the day to look at. Reflector saves these in your config file by default, and the next time you open it, you might find the list getting a bit messy. Marking the files read only solves this.

While we're on the topic, don't forget to look at the Reflector Add-In's project on CodePlex. My personal favourite add-ins are:

I don't think of myself as an ALM guy, but I have worked on a number of projects that happened to use Team Foundation Server. I find customers tend to make use of different features over time:

  1. Initially, they just use the source control feature
  2. Then they start to use automated builds
  3. After a while, they may start to use work items
  4. One day, after a long time, they might start to use reports

One area that is often neglected is the SharePoint project portal. I've seen some teams (notably our internal development centre and the Microsoft SDC) who make great use of the portal, but more commonly it's completely unused.

Recently I decided to customize the portal on a project I was working on, and thought I might share some tips for pimping your TFS project portal.

The goal of the project portal should be to provide easy-access to anything people on the project might need, especially those who don't normally interact with TFS through Visual Studio.

Lists

  1. Environments list
    Most projects will do automated deployment to a number of servers, such as development, test and production. Your project portal home page should show a list of these environments. You might have the following columns:
    • Name of the environment
    • Status (online, temporarily offline, etc.)
    • URL/access instructions
    • Date and build number of the build currently deployed to the server
    • Information about test usernames/passwords if necessary
  2. Active Risks
    I use a simple risk register to track things that need to be done, but can wait a few weeks. Think of them as impediments that we know will take a long time to resolve. Ideally risks would be stored as work items in TFS, but I find it's common that not all stakeholders have a TFS CAL, so a SharePoint list is a good substitute. An example of a risk might be that we need confirmation from a hardware vendor about the specs we have requested - it doesn't block us, but someone needs to resolve it. Potential columns:
    • A title and description
    • The user who will 'own' following up on this risk to ensure it doesn't impact the team
    • The status (not started, in progress, resolved, etc.)
    • The iteration/sprint number before which the risk needs to be resolved
  3. Iteration plan
    Iterations and their work items should be stored in TFS, but I like to show a short list of iterations on the project portal home page. The nice thing about keeping these in a list is you can use them as a "choice" field in some of your other lists:
    • Iteration name (e.g., Iteration 3)
    • Start and end dates
    • A statement of the overall goal of the iteration - e.g., "Patient search and inbox"
    • Any important resourcing notes - e.g., "Jack's last iteration"
  4. Glossary
    On any project there are a number of terms that arise that your everyday "off the street" developer won't understand. If you are doing Domain Driven Design, this might also house your Ubiquitous Language. The glossary is a good place to capture this:
    • Name of the term and a description
    • Whether the term is an industry-specific term, a business-specific term, or a technical term
  5. Important dates
    While the team works to produce the product, stakeholders are often scheduling other things around the project, such as demos, external reviews, dates when new servers will arrive, and so on. It's a good idea to put these on the project portal so that the whole team has an understanding of when these will take place.
  6. Contacts
    Make sure everyone on the team has a way to contact everyone else. If it's an internal team, you might be able to rely on Active Directory to track this, but if your team is made up of a mix of staff, contractors and consultants it might be easier to list contact details on the project portal.
  7. Other things people should know
    On one project, we had a daily standup teleconference at 9:30 AM. I made sure the project portal home page had the time, dial-in numbers and some short rules on what is expected of people in the standup.
  8. Retrospective Feedback
    At the end of an iteration, it's a good idea to hold a retrospective with the team. We use this to brainstorm ways to improve how the team works. Rather than just capture these in your notepad, add them to a SharePoint list:
    • A title and description
    • Iteration number
    • Category (something we did well, something we should start doing, something we should stop doing)

When you do the next retrospective, you can bring up the previous round of suggestions to see whether you successfully stuck to them or not.

Wiki

You might intend to use word documents for Formal Documentation later in the project, but a wiki is a perfect way for the team to collaborate on documentation and keep them up to date while the project progresses and things change rapidly.

Some important things any project wiki should contain:

  • Getting Started
    When a new developer joins your project, there should be a single page that helps them to get started and be productive. It will tell them:
    • The TFS connection to use
    • The TFS path from which to get latest
    • The solution to open
    • Steps to get the project to compile and run
    • Links and licenses for any third party tools or libraries they will have to install
    • If your project has custom tools that developers need to use to be productive, such as code generators, include documentation on how to use those
  • Communication manifesto
    If your team is centrally located, this might not be so necessary. If team members work from different floors or remotely, you might find it worthwhile to capture this:
    • If you do a daily standup, explain the rules of the standup, and what time it starts
    • You might hold a sprint kickoff meeting at the start of every sprint, or a retrospective at the end. Make sure these are listed.
    • If your team is doing remote standups by teleconference or email
    • If you are using work items in TFS, make sure people know to update these regularly, such as daily
    • Let people know what you expect to see in check-in comments. For me, I need to see at least a full sentence. Hold up some examples of good checkin comments, and try to lead by example!
    • Let people know how to use "ambient" communications, like check-in notifications and work item reports, to stay abridge of project progress
    • If you are doing code reviews, put some tips on how to ask for and conduct a review
      1. Standards, practices and principles
        If you have a larger team or a team with higher than usual turnover, it's good to capture some of the standards you have.
    • Coding standards. I hate long coding standards documents, but then can usually be standardized in about five or six points: this is how we name private fields, for everything else, do what ReSharper suggests. Class names and namespaces should match file names and folders. That's all we need.
    • Principles the team should be aware of. Uncle Bob's SOLID principles are a good start.

Needless to say, you can track most of this information in other places, and you don't need to use TFS or even SharePoint for any of this. But if you are using TFS, you probably already have a SharePoint portal, so why not make the most of it?

If you are using your project portal, what other items would you add to this list?

Special thanks to Darren Neimke and Mitch Denny for the communication manifesto area, which I picked up from the way they ran our internal development portal.

Also, I do apologize for posting about SharePoint - I promise it's a once-off and I'll stick to WPF :)

When creating new projects, especially when using new technologies or patterns, it's common to start with a very horizontal or layer-based folder structure:

An example of a layer-based folder structure, with folders for each layer in the project

As the project evolves artifacts are added to each folder. Over time, I find this structure becomes hard to work with:

  • When editing a view and needing to find the view model, there's a lot of scrolling involved
  • If I decide to split an area of functionality into a different assembly, it's not so easy to track down the files I need
  • I'm much more likely to need to edit all of the "change address" artifacts than I am to edit all of the "view model" artifacts in a single unit of work.

My preference is to structure projects vertically by feature, using a folder per feature:

An example of a feature-based folder structure, with folders for each feature in the project

I gave two user group presentations in Sydney this week:

Thanks to those who could make it. You can find the slides and code samples in Subversion here:

This week I have been working on a routing system for Magellan. The goal was to make it very similar to ASP.NET's style of routing:

Routes.Register("Default", 
    "{controller}/{action}/{id}",                            // Path specification
    new { controller = "Home", action = "Index", id = "" },  // Defaults
    new { id = "^[0-9]+$" }                                  // Constraints
);

Unfortunately, I hadn't counted on Silverlight's security implementation. Since anonymous types are internal, I can't use reflection to pull apart the defaults and constraints the way ASP.NET MVC does.

Which of these syntaxes do you prefer?

Routes.Register("Default", "{controller}/{action}/{id}")
    .Defaults(controller => "Home", action => "Index", id => "")
    .Constraints(id => "^[0-9]+$");

Routes.Register("Default", 
    "{controller}/{action}/{id}",
    new Defaults(controller => "Home", action => "Index", id => ""),
    new Constraints(id => "^[0-9]+$")
);

Alternatively, please suggest a better alternative :)

Richard Banks started a podcast series with a focus on Australian developers called Talking Shop. Last week he was kind enough to interview me about WPF, Magellan, and a number of other (un)related topics.

Talking Shop Episode 5

Don't forget to check out the earlier episodes:

The OzWPF mailing list is a place for Australians with an interest in Windows Presentation Foundation to connect, share and discuss WPF, and promote local WPF events.

The list is hosted by the kind folks at Codify. You can subscribe by sending an email to:

ozwpf-subscribe@list.ozwpf.com

Or from the self help portal:

http://prdlxvm0001.codify.net/mailman/listinfo/ozwpf

International WPF enthusiasts are also welcome. You can help by re-blogging or sharing this post with your co-workers :)

Look forward to seeing you there!

The latest CodePlex Magellan build includes a couple of changes that are worth noting:

  1. The new Forms controls
  2. No need to import the Magellan namespaces
  3. Various bug fixes

That second item is worth focusing on. In previous builds, to use any of the Magellan classes in XAML, you had to write:

<Page ...
    xmlns:magellan="http://xamlforge.com/magellan"
    >
    <magellan:Layout...

I wrote before about an idea to move them to the default XAML namespace, and while a few potential issues were suggested, I thought the benefits outweighed the issues. This means you can now do this:

<Page ...
    <Layout ...

With the new Forms feature combined with the Shared Layouts feature, the markup gets really minimal:

<Page ...>
    <Layout>
        <Zone ZonePlaceHolderName="Content">
            <Form>
                <Field For="{Binding FirstName}" />
                <Field For="{Binding LastName}" />
                <Field For="{Binding EmailAddress}" />
            </Form>
        </Zone>
        <Zone ZonePlaceHolderName="Actions">
            <Button Content="Submit" Command="{Binding Submit}" />
        </Zone>
    </Layout>
</Page>

If you do encounter any issues because of this change, please let me know.

Back to: Magellan Home

Data entry forms are common in line of business WPF applications, and they can become repetitive to write. Magellan includes a new set of controls that you can use to rapidly throw data entry forms together.

The goals of Magellan Forms are:

  • Minimal XAML
  • Abstract presentation concerns
  • Use conventions to infer as much information as possible
  • Flexible and extensible

Getting Started

To illustrate, take a form declared like this:

<Form>
    <Field For="{Binding Path=Server.Server}" />
    <Field For="{Binding Path=Server.CachedExchangeMode}" />
    <Field For="{Binding Path=Server.Username}" />
    <Field For="{Binding Path=Server.SecurityMode}" />
</Form>

The object model that this form is bound to looks like this:

public class ExchangeServerSettings : ServerSettings
{
    public string Server { get; set; }

    public string Username { get; set; }

    [DisplayName("Use cached Exchange mode")]
    public bool CachedExchangeMode { get; set; }

    [DisplayName("Security mode")]
    public ExchangeSecurityMode SecurityMode { get; set; }
}

public enum ExchangeSecurityMode
{
    [EnumDisplayName("Negotiate")]
    Negotiate,
    [EnumDisplayName("NTLM")]
    Ntlm,
    [EnumDisplayName("Kerberos")]
    Kerberos
}

This markup and code is all Magellan Forms needs to figure out how to render the form:

A WPF form. Notice how the checkbox and

Magellan was able to infer:

  • The caption for each field, using either the DisplayName attribute or property name.
  • The control to use for each field, based on the control type

Overriding

While Magellan Forms is able to infer settings based on the bindings, the feature is optional. You can instead manually set all of the field values:

<Field Header="First name:">
    <TextBox Text="{Binding Path=FirstName}" Width="200" />
</Field>

Fields are just ContentControls, so you can use anything you like inside a field. You can also choose to infer most of a field while overriding a specific setting, for example:

<Field Header="Surname:" For="{Binding Path=LastName}" />

Styling

A Form is simply an ItemsControl, which by default uses a StackPanel to lay out the children. A Field is a ContentControl. This means you can use styles and templates to customize how they are rendered.

For example, suppose our design team decided that all labels should now be right-aligned:

Now the labels are right-aligned

They just have to override the Field template in App.xaml:

<Style TargetType="Field">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Field">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="120" />
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition Width="*" />
                    </Grid.ColumnDefinitions>

                    <Label Content="{TemplateBinding Header}" HorizontalContentAlignment="Right" Margin="2" />
                    <ContentPresenter Grid.Column="1" />
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Extending

The conventions used to infer control types and display settings can be customized through two extension points:

  1. IFieldConvention, used to figure out the heading and other settings
  2. IEditorStrategy, a list of which is used to create the appropriate editor for a type

You can implement IFieldConvention and then register it via the attached inherited property on a field:

<Form Form.FieldConvention="{x:Static MyFieldConvention.Instance}"> ...

When the default field convention is choosing an editor, it consults a list of registered IEditorStrategy implementations. There are three out of the box:

  1. TextBoxEditorStrategy
  2. ComboBoxEditorStrategy
  3. CheckBoxEditorStrategy

Writing your own is easy. For example, suppose you want to show a masked editor for numeric types. The code below assumes you use something like the Xceed masked editor:

public class MaskedTextBoxEditorStrategy : IEditorStrategy
{
    public object CreateEditor(FieldContext context)
    {
        var isInteger = context.PropertyDescriptor.PropertyType == typeof(int);
        var isDecimal = context.PropertyDescriptor.PropertyType == typeof(decimal);

        if (!isInteger && !isDecimal) 
        {   
            // This editor is only concerned with numeric types 
            return null;
        }

        var maskedTextBox = new MaskedTextBox();
        maskedTextBox.Mask = isInteger ? "999,999" : "999,999.99";
        BindingOperations.SetBinding(maskedTextBox, TextBox.TextProperty, context.FieldBinding);
        return maskedTextBox;
    }
}

The editor then just needs to be registered (usually somewhere in App.xaml.cs):

EditorStrategies.Strategies.Insert(0, new MaskedTextBoxEditorStrategy());

Note that when a field is inferred, all editors are consulted in order, and the first non-null result is used. That's why you typically want to Insert an editor to the top of the list rather than adding it to the end. I'm interested in feedback on this design.

Validation

Editor strategies can also make use of validation attributes to provide richer information and UI cues. For example, suppose you had a standard range of TextBox sizes:

<Style x:Key="TextBox.Small" TargetType="TextBox" BasedOn="{StaticResource {x:Type TextBox}}">
    <Setter Property="Width" Value="100" />
</Style>

<Style x:Key="TextBox.Normal" TargetType="TextBox" BasedOn="{StaticResource {x:Type TextBox}}">
    <Setter Property="Width" Value="200" />
</Style>

<Style x:Key="TextBox.Big" TargetType="TextBox" BasedOn="{StaticResource {x:Type TextBox}}">
    <Setter Property="Width" Value="300" />
</Style>

The view model could use make use of Data Annotations to specify the maximum text length and whether a field is mandatory:

[Required]
[StringLength(30)]
public string Username { get; set; }

A custom editor strategy could detect these and set the TextBox settings as follows:

public class CustomTextBoxEditorStrategy : IEditorStrategy
{
    public object CreateEditor(FieldContext context)
    {
        if (context.PropertyDescriptor.PropertyType != typeof(string))
        {
            // We only deal with strings
            return null;
        }

        var required = context.PropertyDescriptor.Attributes.OfType<RequiredAttribute>().FirstOrDefault();
        var length = context.PropertyDescriptor.Attributes.OfType<StringLengthAttribute>().FirstOrDefault();

        if (required != null)
        {
            context.Field.IsRequired = true;
        }

        var textBox = new TextBox();
        BindingOperations.SetBinding(textBox, TextBox.TextProperty, context.Binding);
        if (length != null)
        {
            var max = length.MaximumLength;
            if (max < 20) textBox.Style = (Style)context.Field.FindResource("TextBox.Small");
            else if (max < 50) textBox.Style = (Style)context.Field.FindResource("TextBox.Normal");
            else textBox.Style = (Style)context.Field.FindResource("TextBox.Big");

            textBox.MaxLength = max;
        }
        return textBox;
    }
}

The editor strategy can also set values on the bindings, such as adding new ValidationRules.

Summary

Magellan Forms provides a foundation that allows you to leverage a little infrastructure code (editor strategies, styles, annotations) to gain a lot of reuse. I like to think of this as 'semantic XAML', that is, the functional XAML just describes that I want a form with some fields, rather than all the specifics about layout. The layout decisions are differed to styles that designers can manage, giving us consistency and a single point of change. I hope you find the feature useful.

Note for partial trust applications

Inference relies on invoking a private member on BindingExpression to work. This means it won't work in XBAP's and other partial trust scenarios. The rest of the forms library should work - just don't use the For property.

Thanks

I'd like to thank my colleague, Miguel Madero, who worked with me to figure out how inference would work.

Back to: Magellan Home

On Thursday, 25th of February, I gave a talk at the Sydney Architecture User Group. The topic was things architects and lead developers should consider when building applications that use WPF.

Abstract:

.NET 4.0 will mark the fourth release of Windows Presentation Foundation, and the take up continues to rise as the platform matures. For architects, such a new technology means a new set of patterns, approaches and trade-offs that we need to understand when designing solutions. In this session, Paul will lead you on a guided tour of the WPF client application problem space. We will look at patterns for presentation, composition, navigation, and communication needs, as well as resource management, localization, and performance. We will also look at strategies for enforcing UI standards, maximising code leverage, and handling cross-cutting concerns. Bring questions!

More details are at the Sydney Architecture User Group website.

This was a code-free presentation, but here are the slides:

Nice to see so many new and old faces at the event.