Drawing Object Model

With many GUI technologies, applications that want customized visuals are required to be able to re-create their appearance from scratch. The usual technique for showing a custom appearance is to write code that performs a series of drawing operations in order to construct the display. This code runs when the relevant graphics first need to be displayed. In some systems, the OS does not retain a copy of what the application draws, so this method ends up running anytime an area needs repainting—for example, if a window was obscured and then uncovered.

Updating individual elements is often problematic in systems that use this on-demand rendering style. Even where the OS does retain a copy of the drawing, it is often retained as a bitmap. This means that if you want to change one part of the drawing, you often need to repaint everything in the area that has changed.

WPF offers a different approach: you can add objects representing graphical shapes to the tree of user interface elements. Shape elements are objects in the UI tree like any other, so your code can modify them at any time. If you change some property that has a visual impact—such as the size, location, or color—WPF will automatically update the display.

To illustrate this technique, Example 13-4 shows a simple window containing several ellipses. Each is represented by an Ellipse object, which we will use from the code-behind file to update the display.

Example 13-4. Changing graphical elements

<Window x:Class="ChangeItem.MainWindow"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Change Item">

<Canvas x:Name="mainCanvas">

Example 13-4. Changing graphical elements

<Window x:Class="ChangeItem.MainWindow"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Change Item">

<Canvas x:Name="mainCanvas">

<Ellipse

Canvas.

.Left="10" Canvas.Top=

"30"

Fill='

'Indigo"

Width='

'40" Height="20" />

<Ellipse

Canvas.

.Left="20" Canvas.Top=

"40"

Fill='

'Blue"

Width='

'40" Height="20" />

<Ellipse

Canvas.

.Left="30" Canvas.Top=

"50"

Fill='

'Cyan"

Width='

'40" Height="20" />

<Ellipse

Canvas

.Left="40" Canvas.Top=

"60"

Fill='

'LightGreen

Width='

'40" Height="20" />

<Ellipse

Canvas

.Left="50" Canvas.Top=

"70"

Fill=

'Yellow"

Example 13-5 shows the code-behind file for this window. It attaches a handler to the main canvas's MouseLeftButtonDown event. Thanks to event bubbling, this OnClick handler method will be called whenever any of the ellipses is clicked. This method simply increases the Width property of whichever Ellipse raised the event. The result is that clicking on any ellipse will make it wider.

Example 13-5. Changing a shape at runtime using System.Windows; using System.Windows.Shapes;

namespace Changeltem {

public partial class MainWindow : Window { public MainWindow() : base() { InitializeComponent(); mainCanvas.MouseLeftButtonDown += OnClick;

private void OnClick(object sender, RoutedEventArgs e) { Ellipse r = e.Source as Ellipse; if (r != null) { r.Width += 10;

If we were using the old approach of drawing everything in a single rendering function, this code would not be sufficient to update the display. It would normally be necessary to tell the OS that the screen is no longer valid, causing it to raise a repaint request. But in WPF, this is not necessary—when you set a property on an Ellipse object, it ensures that the screen is updated appropriately. Moreover, WPF is aware that the items overlap, as shown in Figure 13-4, so it will also redraw the items beneath and above as necessary to get the right results. All you have to do is adjust the properties of the object.

Figure 13-4. Changing overlapping ellipses

Even though computer memory capacities have increased by orders of magnitude since GUIs first started to appear, in some situations this object model approach for drawing still might be too expensive. In particular, for applications dealing with vast data sets such as maps, having a complete set of objects in the UI tree mirroring the structure of the underlying data could use too much memory. Also, for certain kinds of graphics or data, it may be more convenient to use the old style of rendering code.

Because of this, WPF also supports some lighter weight modes of operation. The "Visual Layer Programming" section, later in this chapter, describes the on-demand rendering mechanisms. The "DrawingBrush" section, also later in this chapter, describes a third technique that is somewhere in between the two, trading off a little flexibility in exchange for better performance—it offers many of the benefits of a retained model, but without the overhead of a full WPF framework element.

You may have noticed that all of the drawing we've done so far has been with shapes and not bitmaps. WPF supports bitmaps, of course, but there is a good reason to use shapes—you can scale and rotate geometric shapes without losing image quality. This ability to perform high-quality transforms is an important feature of drawing in WPF.

Was this article helpful?

0 0
Project Management Made Easy

Project Management Made Easy

What you need to know about… Project Management Made Easy! Project management consists of more than just a large building project and can encompass small projects as well. No matter what the size of your project, you need to have some sort of project management. How you manage your project has everything to do with its outcome.

Get My Free Ebook


Post a comment