Table of Contents
| Ch. 1 | .NET architecture | 3 |
| Ch. 2 | C# basics | 29 |
| Ch. 3 | Objects and types | 83 |
| Ch. 4 | Inheritance | 109 |
| Ch. 5 | Operators and casts | 131 |
| Ch. 6 | Delegates and events | 167 |
| Ch. 7 | Memory management and pointers | 187 |
| Ch. 8 | Strings and regular expressions | 217 |
| Ch. 9 | Collections | 239 |
| Ch. 10 | Reflection | 257 |
| Ch. 11 | Errors and exceptions | 277 |
| Ch. 12 | Visual Studio .NET | 301 |
| Ch. 13 | Assemblies | 339 |
| Ch. 14 | .NET security | 391 |
| Ch. 15 | Threading | 439 |
| Ch. 16 | Distributed applications with .NET remoting | 455 |
| Ch. 17 | Localization | 509 |
| Ch. 18 | Deployment | 545 |
| Ch. 19 | Windows forms | 573 |
| Ch. 20 | Graphics with GDI+ | 623 |
| Ch. 21 | Data access with .NET | 685 |
| Ch. 22 | Viewing .NET data | 735 |
| Ch. 23 | Manipulating XML | 781 |
| Ch. 24 | Working with active directory | 837 |
| Ch. 25 | ASP.NET pages | 873 |
| Ch. 26 | Web services | 909 |
| Ch. 27 | User controls and custom controls | 931 |
| Ch. 28 | COM interoperability | 965 |
| Ch. 29 | Enterprise services | 999 |
| Ch. 30 | File and registry operations | 1025 |
| Ch. 31 | Accessing the Internet | 1067 |
| Ch. 32 | Windows services | 1091 |
| App. A | Principles of object-oriented programming | 1137 |
| App. B | C# for Visual Basic 6 developers | 1177 |
| App. C | C# for Java developers | 1225 |
| App. D | C# for C++ developers | 1253 |
Read an Excerpt
21: Graphics with GDI+
This is the second of the two chapters in this book that covers the elements of interacting directly with
the user, that is displaying information on the screen and accepting user input via the mouse or
keyboard. In Chapter 9 we focused on Windows Forms, where we learnt how to display a dialog box or
SDI or MDI window, and how to place various controls on it such as buttons, text boxes, and list boxes.
In that chapter, the emphasis was very much on using the familiar predefined controls at a high level
and relying on the fact that these controls are able to take full responsibility for getting themselves
drawn on the display device. Basically, all you need to do is set the controls' properties and add event
handlers for those user input events that are relevant to your application. The standard controls are
powerful, and you can achieve a very sophisticated user interface entirely by using them. Indeed, they
are by themselves quite adequate for the complete user interface for many applications, most notably
dialog-type applications, and those with explorer style user interfaces.
However there are situations in which simply using controls doesn't give you the flexibility you need in your
user interface. For example, you may want to draw text in a given font in a precise position in a window, or
you may want to display images without using a picture box control, simple shapes or other graphics. A good
example, is the Word for Windows program that I am using to write this chapter. At the top of the screen are
various menus and toolbars that I can use to access different features of Word. Some of these menus and
buttons bring up dialog boxes or even property sheets. That part of the user interface is what we covered in
Chapter 9. However, the main part of the screen in Word for Windows is very different. It's an SDI window,
which displays a representation of the document. It has text carefully laid out in the right place and displayed
with a variety of sizes and fonts. Any diagrams in the document must be displayed, and if you're looking at
the document in Print Layout view, the borders of the actual pages need to be drawn in too. None of this can
be done with the controls from Chapter 9. To display that kind of output, Word for Windows must take
direct responsibility for telling the operating system precisely what needs to be displayed where in its SDI
window. How to do this kind of thing is subject matter for this chapter.
We're going to show you how to draw a variety of items including:
- Lines, simple shapes.
- Images from bitmap and other image files.
- Text.
In all cases, the items can be drawn wherever you like within the area of the screen occupied by your
application, and your code directly controls the drawing – for example when and how to update the
items, what font to display text in and so on.
In the process, we'll also need to use a variety of helper objects including pens (used to define the
characteristics of lines), brushes (used to define how areas are filled in – for example, what color the
area is and whether it is solid, hatched, or filled according to some other pattern), and fonts (used to
define the shape of characters of text). We'll also go into some detail on how devices interpret and
display different colors.
The code needed to actually draw to the screen is often quite simple, and it relies on a technology called
GDI+. GDI+ consists of the set of .NET base classes that are available for the purpose of carrying out
custom drawing on the screen. These classes are able to arrange for the appropriate instructions to be
sent to the graphics device drivers to ensure the correct output is placed on the monitor screen (or
printed to a hard copy). Just as for the rest of the .NET base classes, the GDI+ classes are based on a
very intuitive and easy to use object model.
Although the GDI+ object model is conceptually fairly simple we still need a good understanding of the
underlying principles behind how Windows arranges for items to be drawn on the screen in order to
draw effectively and efficiently using GDI+.
This chapter is broadly divided into two main sections. In the first two-thirds of the chapter we will
explore the concepts behind GDI+ and examine how drawing takes place, which means that this part of
the chapter will be quite theoretical, with the emphasis on understanding the concepts. There will be
quite a few samples, almost all of them very small applications that display specific hard-coded items
(mostly simple shapes such as rectangles and ellipses). Then for the last third of the chapter we change
tack and concentrate on working through a much longer sample, called CapsEditor, which displays
the contents of a text file and allows the user to make some modifications to the displayed data. The
purpose of this sample, is to show how the principles of drawing should be put into practice in a real
application. The actual drawing itself usually requires little code – the GDI+ classes work at quite a high
level, so in most cases only a couple of lines of code are required to draw a single item (for example, an
image or a piece of text). However, a well designed application that uses GDI+ will need to do a lot of
additional work behind the scenes, that is it must ensure that the drawing takes place efficiently, and
that the screen is updated when required, without any unnecessary drawing taking place. (This is
important because most drawing work carries a very big performance hit for applications.) The
CapsEditor sample shows how you'll typically need to do much of this background management.
The GDI+ base class library is huge, and we will scarcely scratch the surface of its features in this
chapter. That's a deliberate decision, because trying to cover more than a tiny fraction of the classes,
methods and properties available would have effectively turned this chapter into a reference guide that
simply listed classes and so on. We believe it's more important to understand the fundamental principles
involved in drawing; then you will be in a good position to explore the classes available yourself. (Full
lists of all the classes and methods available in GDI+ are of course available in the MSDN
documentation.) Developers coming from a VB background, in particular, are likely to find the concepts
involved in drawing quite unfamiliar, since VB's focus lies so strongly in controls that handle their own
painting. Those coming from a C++/MFC background are likely to be in more comfortable territory
since MFC does require developers to take control of more of the drawing process, using GDI+'s
predecessor, GDI. However, even if you have a good background in GDI, you'll find a lot of the
material is new. GDI+ does actually sit as a wrapper around GDI, but nevertheless GDI+ has an object
model which hides many of the workings of GDI very effectively. In particular, GDI+ replaces GDI's
largely stateful model in which items were selected into a device context with a more stateless one, in
which each drawing operation takes place independently. A Graphics object (representing the device
context) is the only object that persists between drawing operations.
By the way, in this chapter we'll use the terms drawing and painting interchangeably to describe the
process of displaying some item on the screen or other display device.
Before we get started we will quickly list the main namespaces you'll find in the GDI+ base classes. They are...
...Almost all the classes, structs and so on. we use in this chapter will be taken from the System.Drawing
namespace.
Understanding Drawing Principles
In this section, we'll examine the basic principles that we need to understand in order to start drawing to
the screen. We'll start by giving an overview of GDI, the underlying technology on which GDI+ is
based, and see how it and GDI+ are related. Then we'll move on to a couple of simple samples.
GDI and GDI+
In general, one of the strengths of Windows – and indeed of modern operating systems in general – lies
in their ability to abstract the details of particular devices away from the developer. For example, you
don't need to understand anything about your hard drive device driver in order to programmatically
read and write files to disk; you simply call the appropriate methods in the relevant .NET classes (or in
pre-.NET days, the equivalent Windows API functions). This principle is also very true when it comes to
drawing. When the computer draws anything to the screen, it does so by sending instructions to the
video card telling it what to draw and where. The trouble is that there are many hundreds of different
video cards on the market, many of them made by different manufacturers, and most of which have
different instruction sets and capabilities. The way you tell one video card to draw, for example a simple
line or a character string may involve different instructions from how you would tell a different video
card to draw exactly the same thing. If you had to take that into account, and write specific code for
each video driver in an application that drew something to the screen, writing the application would be
an almost impossible task. Which is why the
Windows Graphical Device Interface (GDI) has always
been around since the earliest versions of Windows....