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
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.
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.
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);
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)
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...|