Tuesday, November 18, 2008

WPF Back to Basics - Panels

Something I am noticing amongst my WPF peers is limited knowledge of the layout tools available to us in WPF. Most of us come from a Win Forms or ASP.NET background to relate to a few concepts:

  1. Absolute positioning
  2. Table positioning

I have very limited experience in Win Forms programming but all the stuff I have done with has been absolute positioning eg this control is x pixels from the Left/Right and y pixels from Top/Bottom. In my ASP.NET career I have seen plenty of way to create layout from everyone's first love; tables, to frames, IFrames, Lists and divs (remember Layers anyone?).

Well WPF really brings a lot more to the table than that lot of layout options. Remember that HTML has kinda evolved to being what it is with CSS tacked on to help layout. It originally was a markup language for describing content not really for fancy presentation. WPF however was built ground up for fancy presentation.

Lets look at some of the layout options we have available to us out of the box and when each would be useful:

Grid

The grid is similar to a Table in HTML, similar but not the same. In a grid you specify how many rows and columns the grid will have. You then set an attached property on each of the child elements specifying which row and column (zero based index) it belongs to. Failure to do so will default in the value of 0 being assumed meaning it will displayed in the first row/column.

Grid also has the interesting feature that allows you to stack things in a z index. For example if you specify two things to appear in the same cell then the elements are piled on top of each other with the last element specified being on top. This can be useful in some scenarios, but generally is a mistake when a dev forgets to specify the correct column and row attached properties

When to use Grid?

I find that the Grid has been most useful to me when I need to display a form to fill in. Generally I have a Label in column 0, the field in column 1 and maybe a validation message in column 3. It also offers star notation for its column and row size values which can be nice for dynamic resizing of layouts.

Canvas

Canvas is a similar to absolute positioning in HTML/CSS. You just provide Left/Right and Top/Bottom coordinates. There are no boundaries so you provide any kind of values eg negative or very large. I find the canvas the least useful panel for the work I do. However it is showcased very nicely in the FamilyShow application by Vertigo.

When to use Canvas?

I would use canvas if I wanted to throw stuff on to a conceptual whiteboard or desktop. This would be great where the user could just drag things around and not have to be constrained by a less organic structure like a grid.

StackPanel

StackPanel is one of the simplest but best tools in your layout panel arsenal. It simply stacks its children one after the other in the orientation you specify. The  Orientation options are Horizontal and Vertical (the default). In a web world this would be like just placing a bunch of items in successive black elements (div tags). If we set the orientation to Horizontal then it would more similar to using span tag except in WPF the StackPanel will not wrap when it runs out of room. Also note that the StackPanel will take up as much room as it needs, but never any more room than it needs, so don't use StackPanel where you want a fill effect.

When to use the StackPanel?

Everywhere! ;-) I find that the StackPanel is great for Templates where I may want to stack a Header, a summary and a description for example. There are also useful when bundling text blocks together quickly where you may want "X by Y pixels" you can stack horizontally four text blocks of which two are bound to Width and Height properties.

WrapPanel

The WrapPanel is the answer when the StackPanel has scrolled of the edge of the screen because it has taken too much room. As I pointed out above the StackPanel will also take the space it needs, the WrapPanel however will respect one dimension and wrap to a new line of controls when it runs out of room in that dimension.

When to use the WrapPanel?

My favourite use of the WrapPanel is to replace an ItemPanelTemplate for an ItemsPanel property in an ItemsControl. Sorry if that makes very little sense. Lets provide some background; when you use an ItemsControl (or one of its inherited controls like ListBox, ListView, Selector etc) by default all of the Items it displays are just display one after the other in a vertical direction. That is because the implementation uses a StackPanel do do its dirty work. However by changing the ItemPanelTemplate we can have it use a WrapPanel instead. So? Well this is really sweet for when we want to display things like Thumbnail pictures. When we use the WrapPanel we get an effect like in Windows Explorer when you view images within a folder as thumbnails which displays images left to right and then when there is no more space it wraps to the next line and continues showing the images. If there are too many images for the page then a vertical scroll bar will be displayed.

DockPanel

DockPanel is one of the un-sung hero's of WPF layout. The general idea behind the DockPanel is that the control will fill the area it is given, and then allow its children to "dock" themselves to one of it's four sides (Left, Right, Top and Bottom). DockPanel uses a first-in-first-served notion. If I have a DockPanel and the first child of the DockPanel wants to dock to the right, it will take up as much horizontal space as it requests and 100% of the height of the DockPanel. If the next child wanted to dock to the Bottom then It would recieve as much vertical space that it needed and the remaining horizontal space left from the first child. Generally the last child is provided the remaining available space.

When to use the DockPanel?

The DockPanel is an underused panel in my experience. Many complex implementations using Grids with fixed column and row widths and then an Auto sized column and row in the middle for content should have used a DockPanel. I would imagine a large majority of applications now have a toolbar at the top, a status bar at the bottom, some menu system down the left and/or right side. This common layout just screams DockPanel.

 

Other notable mentions...

While this post is mainly about panels, the intention is to uncover the possibilities before you by having a better knowledge of WPF, because of that I think it is worth talking about some other controls that could be useful.

TabControl

Now I bet the first thing you will think is "I know what a tab control is...next.", but stop for just a second. With the power of WPF and it's lookless control sub-system I have seen some talented WPF people put together crazy solutions together where a stylised TabControl would have been fine. Essentially the TabControl is a Selector of headered controls. Select one Head and its contents show.

When to use the TabControl?

When ever you have a piece of functionality that has a set of buttons that stay visible, but pressing on one of them shows a view and hides another view, please consider tab control. An example that many could relate to would be the buttons down the left side of Outlook. When you select the Mail Button, the Mail Button is displayed as selected and the Mail content shows. Now this doesn't look like a normal TabControl but the effect is the same.

Viewbox

I thought I might make mention of this funky control. The Viewbox gives this cool scale effect that most would only associate with the Image control. As with an Image control that allows a Stretch property to be set so that it can scale out to fill the space it has been provided, the Viewbox can wrap another control to provide the same feature. Very cool.

When to use the Viewbox?

Use the view box when you want a control to always be completely visible and scale to the space it has been provided.

Toolbar / ToolbarTray

Toolbar is one of those useful controls to use to give common functionality to your application. Many Microsoft application have a toolbar in them. Visual Studio is a very good example of ToolbarTray and Toolbar usage. VS has an area defined that can house ToolBars. The user can choose which toolbars to show and hide and can even drag them around to change the order they are displayed. You get this for free if you use the ToolbarTray and add Toolbars to it.

When to use the ToolbarTray and Toolbar?

Use the ToolbarTray and the ToolBar controls to get similar functionality to Visual Studios toolbar features. Users feel comfortable with controls the already know and you will have less code to write. remeber you can always change the styles to jazz it up if you need.

Ribbon

The Microsoft Ribbon is now available. I have not played with it myself yet but there are videos from PDC that demo how you can code against the current release. Watch this space...

Thursday, November 13, 2008

Charity work...

Tamir Khason has recently announced that he has left the consulting field, however is still willing to provide his services for the benefit of charity. Much karma too him.

Wednesday, November 12, 2008

How C# 3.0 helps you with creating DSL

Carrying on with the last post on how Method Chaining can help you create a DSL, I thought I would plagiarise some more content that Ian Cooper shared with us last night at the London DNUG.

Ian discussed the simple example of how in some languages it is very easy/readable to do something as simple as creating a DateTime of "20 minutes ago"

Ruby Code :

20.minutes.ago

C# Code:

DateTime.Now.AddMinutes(-20);

To be fair the C# code is not awful, but is less like a DSL and could be made a touch better. So how does C#3.0 help? Extension methods allow us to extend functionality of another type that we may not have defined. So in this example we can migrate to a Ruby style by implementing 2 extension methods.

public static TimeSpan Minutes(this int numberOfMinutes)
{
    return new TimeSpan(0, numberOfMinutes, 0);
}

public static DateTime Ago(this TimeSpan numberOfMinutes)
{
    return DateTime.Now.Subtract(numberOfMinutes);
}

By creating these extension methods we now give int types a new method Minutes() that returns a TimeSpan. We then extend the TimeSpan type to have an Ago() method that returns a DateTime. Very simple stuff that allows us to write code like this

20.Minutes().Ago();

Others have covered this topic before here

Method Chaining to create your DSL

I just attended a London DNUG hosted by Ian Cooper regarding Internal DSLs in C#3.0. It was a very interesting session where Ian covered some very similar content to JP Boodhoo's series of 5 "Demystifying patterns" on DNRTV.com. Firstly Ian Covered simply what a DSL is and how there can be DSL internal to .NET. His examples were RhinoMock (and nMock), LINQ and implementations of a fluent API using strategy patterns and method chaining.

While I have seen people use method chaining before primarily in demos or when I have been using RhinoMocks but I have never heard any guidance on how to construct them. As a quick intro to method chaining and why they constitute a DSL here is an example similar to Ian's.

In this example we create a Meeting type using a MeetingBuilder.

var meeting = new MeetingBuilder()
    .On("C# Internal DSLs")
    .By("Ian Cooper")
    .And("Someone else")
    .At( new Address()
        {
            Street1 = "Skills Matter"
            Street2 = "1 something lane"
            PostCode = "SE1ABC"
        })
    .From(new DateTime(2008, 11, 11, 18, 30))
    .Until(new DateTime(2008, 11, 11, 20, 00))
    .Create();
The general Idea here is that we create something that looks more like English language than standard C# code.

So having shown a simple example of Method chaining, I think it is fair to say that it is quite readable and that non technical people (eg Mum) could probably figure out what I am doing here

Ian Copper and somebody else is presenting "C# Internal DSLs" at Skills Matter on 18:30 11th Nov.

If we analyse the code, first thing I would like to mention is that Ian recommends that all methods from a chaining builder (in this case MeetingBuilder) should return this except the Create() method that returns the final object. Now having considered this, that means that we can deduce that MeetingBuilder has a method On(string). Now considering that On(string) is a method on a Builder it should also return the Builder. Cool. By that rational we can also deduce that By(string), And(string), At(Address), From(DateTime), To(DateTime) and Create() are all methods on MeetingBuilder.

Well that is not so interesting until we consider that if we want to create a really fluent API. For the API to be fluent it should not only be readable, we should provide guidance for consuming it too. Referring back to the example we can see the we probably have mandatory method calls and optional methods. In this case only the And(string) method is optional, all of the others should be mandatory. So how can we drive the consumer/developer to know how to use the API if all methods return this?
The answer : Interfaces.

By setting the return types of the methods to interfaces, we can constrain what the next method can do. We still return this, which then tells us we need to implement a bunch of interfaces. The first method this example requires is On(string) so we need an interface like:

interface IMeetingSubjectBuilder
{
    object On(string);
}

but we cant just return object, we need to return an interface that guides the developer to provide the name of the presenter so we expand our interface definitions

interface IMeetingSubjectBuilder
{
   IMeetingPresenterBuilder On(string subject);
}
interface IMeetingPresenterBuilder
{
    IMeetingPresenterOrAddressBuilder By(string presenter);
}
interface IMeetingPresenterOrAddressBuilder 
{
    IMeetingPresenterOrAddressBuilder And(string otherPresenter);
    IMeetingFromTimeBuilder At(Address address);
}

In the above step we have actually done a few things. Firstly we have swapped out the rubbish return type of object for the IMeetingPresenterBuilder. This will then guide our developers to use the methods on that interface. Next we declare that new interface has the By(string) method. This method returns a third interface. The third interface provides two methods. The first method is the And(string) method that allows us to provide additional presenters. Note that its return type is the interface that defines it, which allows a us to recursively call it to add multiple presenters. The second method provides a way to continue providing Address data and eventually other data.

To jump ahead quickly, here is what the final set of interfaces might look like

interface IMeetingSubjectBuilder
{
   IMeetingPresenterBuilder On(string subject);
}
interface IMeetingPresenterBuilder
{
    IMeetingPresenterOrAddressBuilder By(string presenter);
}
interface IMeetingPresenterOrAddressBuilder 
{
    IMeetingPresenterOrAddressBuilder And(string otherPresenter);
    IMeetingFromTimeBuilder At(Address address);
}
interface IMeetingFromTimeBuilder
{
    IMeetingToTimeBuilder From(DateTime startTime);
}
interface IMeetingToTimeBuilder
{
    IMeetingCreator Until(DateTime endTime);
}
interface IMeetingCreator
{
    Meeting Create();
}

Well this is good progress, so all we have to do now is declare a class that implements these interfaces.

class MeetingBuilder : IMeetingSubjectBuilder, IMeetingPresenterBuilder, IMeetingPresenterOrAddressBuilder, IMeetingFromTimeBuilder, IMeetingToTimeBuilder, IMeetingCreator
{
    public IMeetingPresenterBuilder On(string subject){...}
    public IMeetingPresenterOrAddressBuilder By(string presenter){...}
    public IMeetingPresenterOrAddressBuilder And(string otherPresenter){...}
    public IMeetingFromTimeBuilder At(Address address){...}
    public IMeetingToTimeBuilder From(DateTime startTime){...}
    public IMeetingCreator Until(DateTime endTime){...}
    public Meeting Create() {...}
}

One final problem here is that if we were to use this as per the first example we would find that we could call any of the methods straight from the constructor which could confuse the developer. To better guide the developer we can simply implement all of the interface explicitly except for IMeetingSubjectBuilder.

class MeetingBuilder : IMeetingSubjectBuilder, 
    IMeetingPresenterBuilder, 
    IMeetingPresenterOrAddressBuilder, 
    IMeetingFromTimeBuilder, 
    IMeetingToTimeBuilder, 
    IMeetingCreator
{
    public IMeetingPresenterBuilder On(string subject){...}
    IMeetingPresenterOrAddressBuilder IMeetingPresenterBuilder.By(string presenter){...}
    IMeetingPresenterOrAddressBuilder IMeetingPresenterOrAddressBuilder.And(string otherPresenter){...}
    IMeetingFromTimeBuilder IMeetingPresenterOrAddressBuilder.At(Address address){...}
    IMeetingToTimeBuilder IMeetingFromTimeBuilder.From(DateTime startTime){...}
    IMeetingCreator IMeetingToTimeBuilder.Until(DateTime endTime){...}
    Meeting IMeetingCreator.Create(){...}
}

Now when we create an instance of MeetingBuilder we are guided as to which methods are valid in which order and have a nice fluent API. From the constructor we have the On(string) method available, then from there we have the By(string) and so on.

Creating a Fluent API (and therefore an internal DSL) does require more work and some extra effort at design time but it does make for very nice coding experience for the end developer. For more information see what the godfather has to say here : http://martinfowler.com/dslwip/MethodChaining.html

Wednesday, November 5, 2008

Fail fast

Big Col nails the philosophy of fail fast in his recent blog posts. His first post covers this philosophy at a system level and his second post discusses what you can do in your C#/VB.NET/Java code until fancy Eiffel constructs like spec# make there way in to our languages.