Introduction

 

The first things you notice about WPF is what's missing. Charles Petzold gives a short but not insignificant list:

Much of this doesn't bother me. I thought the colour and font pickers were OLD. I never used the inordinately complicated DataGridView, nor metafiles. Maybe I'll miss the spin control. Maybe it has had its day. Maybe Microsoft are working hard on adding these things, or maybe they don't care. Personally, I think it is a good thing to see baggage dumped. If programs like Photoshop had taken the same approach over the years, they might be a little more intuitive.

Having said that, GDI+ - at which I was becoming a bit of an expert - is also obsolete, and learning the new ways are a little irksome. Some things seem especially complicated, which I shall get on to in a moment.

So, onward and upward. The benefits of WPF over GDI+ are as follows

Drawbacks so far are:

The disconnect between the XAML and code is so that designers can design and coders can code. I'm not sure I'm comfortable with this concept of ever increasing speciality. Most designers I have come across use photoshop to design, and were hard pressed even to create a few HTML tags. I would anticipate only a minority ever coming to terms with XAML. I reserve the right to be wrong here as I have not looked at any design tools like Expression Blend

Onto the specifics

 
Think different!

WPF requires a different way of thinking. It is one of hierarchical composition rather than invalidate and paint. In GDI or GDI+ a program would change something, force an invalidation of the image, then wait for the operating system to call OnPaint, supplying a drawing context upon which everything could be redrawn. I have been writing a piece of software for viewing hierarchies, and this constant change/invalidate was hogging the processor just to redraw one item. This no longer occurs with WPF. There is no repaint. The scene is already composed and the graphics card takes care of redrawing.

This single concept is the root of all subsequent confusion for old hacks like me.

Colours

In GDI+, there was a Color class that did just about everything it needed to do. If you had a bit of text you wanted to convert to a brush, you typed:

SolidBrush brush = new SolidBrush(Color.FromName("Red"));

Now, you have to go a little further

BrushConverter conv = new BrushConverter();
SolidColorBrush brush = (SolidColorBrush)conv.ConvertFromString("Red");

There are also two classes: Color() and Colors(). Color does the functions, Colors contains the named colours.

Scrolling and zooming

Scrolling and zooming in GDI+ wasn't the easiest of tasks. It's a lot easier now thanks to a few classes. Here is an example that scrolls:

            <ScrollViewer x:Name="scrollViewer"
                    HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Auto"
                    >
            	<Canvas Background="White" x:Name="canvas"
                    Height="600"
                    Width="800"
                    />
        </ScrollViewer>
    

There are only 2 gotchas:
1. Make the canvas larger than it really is on screen, otherwise the layouttransform doesn't get through to the scrollbars
2. Use LayoutTransform rather than ScaleTransform to zoom.

Loading cursors

Want to load a cursor? It was obscure enough before with

string curName = "cursors." + cursorName + ".cur";
this.Cursor = new Cursor(GetType(), curName);

Now, you put

string curName = "Animator3.cursors." + cursorName + ".cur";
stream = GetType().Assembly.GetManifestResourceStream(curName);
this.Cursor = new Cursor(stream);

Toolbar spacer

Here are three ways to replace the toolbar spacer

Either use this clunky workaround:

                 <Label Width="5" />
                <Canvas Width="1">
                    <Line X1="0" X2="0" Y1="2" Y2="28" Width="1" Stroke="DarkGray"/>
                </Canvas>
                <Canvas Width="1">
                    <Line X1="0" X2="0" Y1="2" Y2="28" Width="1" Stroke="White"/>
                </Canvas>
                <Label Width="5" />
                <Label>Fill</Label>

or, draw a small bitmap, and use that instead

                  <Image Source="/Animator3;component/images/toolbarspacer.png" 
			Stretch="None" HorizontalAlignment="Center" 
			VerticalAlignment="Center"  Height="25" Width="10" />        
			

or, use the new separator item (can be used on toolbar or in menus)

            <Separator />

Nested splitters

To create a window with a vertical splitter and another horizontal splitter splitting the right hand pane, you need a grid nested within a grid, and two grid splitters.

       <Window x:Class="Example.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Disk Viewer" Height="300" Width="749">
        <DockPanel LastChildFill="True" Margin="0,0,0,0">
            <Grid x:Name="MainGrid">
                <Grid.RowDefinitions>
                    <RowDefinition></RowDefinition>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="120"></ColumnDefinition>
                    <ColumnDefinition Width="3"></ColumnDefinition>
                    <ColumnDefinition></ColumnDefinition>
                </Grid.ColumnDefinitions>
                <GridSplitter Grid.Column="1" Grid.Row="0" 
                    Height="Auto" Width="Auto" HorizontalAlignment="Stretch" 
                    VerticalAlignment="Stretch" />
                
                <Grid Name="SubGrid" Grid.Row="0" Grid.Column="2">
                    <Grid.RowDefinitions>
                            <RowDefinition Height="60"></RowDefinition>
                            <RowDefinition Height="3"></RowDefinition>
                            <RowDefinition Height="*"></RowDefinition>
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition></ColumnDefinition>
                    </Grid.ColumnDefinitions>
                    <GridSplitter Grid.Row="1" Grid.Column="0" 
                        Height="Auto" Width="Auto" HorizontalAlignment="Stretch" 
                        VerticalAlignment="Stretch" />
                </Grid> 
            </Grid>
        </DockPanel>
        </Window>
    
More to come...