A Tale of Two Technologies


In general, text is rendered with a specific font to a specific location, and both Graphics and TextRenderer do that quite nicely. So, you might be wondering why there are two textrendering technologies in the .NET Framework.

The Graphics class's text-rendering capabilities are powerful, but they suffer from several key problems, including weak internationalization support for complex scripts (such as Arabic), a lack of visual consistency between Windows Forms applications and the Windows shell, and performance. Unfortunately, although Microsoft tried, it could not refactor Graphics to solve these problems, because of inherent limitations in the technology. These problems are solved by GDI, however, so Microsoft created TextRenderer to provide a managed wrapper around GDI that, for Windows Forms applications, simplifies access to those features missing from Graphics. The resulting implementation is powerful, and the union of functionality between the two technology sets is reasonably large.

As with most competing technologies, however, the union is not 100%. Instead, each technology is the best tool for a particular job. What follows is a discussion of the key issues you should consider to help you decide.

Shell Consistency

The Windows shell uses GDI to render certain UI elements with a consistent font. For example, given a shell default button font of "Tahoma 8pt," Graphics and TextRenderer produce slightly different results, as illustrated in Figure 6.13

Figure 6.13. Comparing Shell Consistency (with VS05 | Tools | Options Dialog Buttons) (See Plate 14)


If you look closely, you can see that the TextRenderer output is consistent with the font used in the VS05 dialog, unlike Graphics, even though the same font is used:

// ShellConsistencyForm.cs partial class ShellConsistencyForm : Form {   // Draw OK button using Graphics   void gOKButton_Paint(object sender, PaintEventArgs e) {     // Draw button background     ...     // Render text     using( StringFormat format = new StringFormat() )     using( Font font = new Font("Tahoma", 8) ) {       format.Alignment = StringAlignment.Center;       format.LineAlignment = StringAlignment.Center;  e.Graphics.DrawString(    "OK",    font,    Brushes.Black,    this.gOKButton.ClientRectangle,    format);    }   } //Draw OK button using TextRenderer void tOKButton_Paint(object sender, PaintEventArgs e) {   // Draw button background   ...   using( Font font = new Font("Tahoma", 8) ) {     TextFormatFlags format = TextFormatFlags.VerticalCenter |                              TextFormatFlags.HorizontalCenter;        TextRenderer.DrawText(          e.Graphics,          "OK",          font,          this.tOKButton.ClientRectangle,          this.ForeColor,          format);    }   }   ... }


Being consistent with the shell is a great feature for applications in general and for reusable controls in particular. If you need to ensure that your visuals are consistent with the shell, you should prefer TextRenderer.

Internationalization

Shell integration is also important for internationalization-ready applications, which must deal with rendering in a variety of languages, including complex scripts, that are determined by the shell.

A script is the set of characters for a particular language, and a complex script is a script with special processing requirements, including the following:[9]

[9] An outline of complex scripts can be found at http://www.microsoft.com/globaldev/DrIntl/faqs/Complex.mspx#E6 (http://tinysells.com/17).

  • Character reordering. Characters are ordered right-to-left or left-to-right.

  • Contextual shaping. Characters render differently depending on their position within a word or the surrounding characters.

  • Combined characters. One character is composed from several other characters.

  • Diacritics. Character accents that alter the pronunciation of individual characters.

Support for handling these issues is native to GDI and is used by Windows to render text for multiple languages.[10] If you've played with the Windows XP Language Bar and installed various language packs, you're familiar with this. Because TextRenderer wraps GDI, it naturally inherits the ability to render complex scripts with the same accuracy as Windows. Although you can render text for complex scripts using Graphics, you are unlikely to achieve the same level of quality as TextRenderer because of GDI+ limitations. Figure 6.14 demonstrates the difference in quality when you render Sinhala script using an appropriate font.

[10] Specifically, the Windows Unicode Script Processor, or Uniscribe (usp10.dll) in Windows XP.

Figure 6.14. Comparing Complex Script Output (Script=Sinhala, Font=DinaminaUniWeb 30pt)


In Figure 6.14, you can see that Sinhala uses combined characters, and Graphics can't combine characters while TextRenderer can.[11] From this example, it is clear that you should favor TextRenderer if your Windows Forms applications or custom controls require custom text rendering and need to support internationalization.

[11] http://si.wikipedia.org/wiki/Wikipedia:Sinhala_font (http://tinysells.com/18). Thanks to Miguel Lacouture-Amaya from Microsoft for help in creating the complex script sample.

Device-Independent Drawing

Internationalization attempts to provide language independence. Another type of independence that is a key feature of GDI+ and the Graphics object is device independence. This means that you render to a logical surface provided by the Graphics object, which wraps and paints to a physical surface, such as a screen or a printer. Consequently, the Graphics object you are handed has intimate knowledge of the physical surface, including the units to draw in, such as pixels (screen) or dpi (printer). Such intimacy allows you to draw to the Graphics object, which then performs scaling as required to match the units of the physical surface to which your stylings are eventually rendered. Thus WYSIWYG (what you see is what you get) is enabled. Figure 6.15 shows that what you see in a text box is what you get when printed, without the need to write any code other than drawing a string to a Graphics object using Graphics.DrawString.

Figure 6.15. Graphics.DrawString Rendering Text to a Printer (Output Scanned) at Same Font as Text Box


From a device point of view, TextRenderer has no concept of independence. It was designed and built to render to one device, the screen, and this means that it knows only one set of units (pixels) and one scale. This subverts WYSIWYG, as shown in Figure 6.16

Figure 6.16. TextRenderer.DrawText Rendering Text to a Printer (Output Scanned) at Same Font as Text Box


If you want to use a TextRenderer to output to a different device, such as a printer, you need to convert the scale of your output to suit the target device. Although it's possible to do this, it's problematic for two reasons. First, you need to write one set of code to scale your TextRenderer output for each device you intend to target. Second, any manual scaling may lead to a loss of precision that will affect your ability to support WYSIWYG output. Therefore, for WYSIWYG output to multiple devices, Graphics provides a more accurate and simplified model.

Font Edge Smoothing Support

Certain devices have special text-rendering considerations beyond scaling. For example, LCD screens produce blocky text output that needs font edge smoothing technology to make it more visually appealing. Windows XP supports three smoothing modes: no smoothing, "Standard" smoothing, and "ClearType" smoothing.[12]

[12] These can be set from Control Panel | Display | Appearance | Effects.

Both Graphics and TextRenderer render text to suit the current smoothing mode without intervention on your part. Up to a point, they are comparable. Table 6.4 illustrates the effect of no smoothing, Standard smoothing, and ClearType smoothing for both text-rendering technologies, using a "Microsoft Sans Serif 70 pt" character.

Table 6.4. Font Edge Smoothing by Text-Rendering Technology

Text-Rendering Technology

Font Edge Smoothing Type

None

Standard

ClearType

Graphics

TextRenderer


As you can see, the two technologies are equivalent for no smoothing and Standard smoothing. However, things go awry when ClearType is the smoothing mode.

For no apparent reason, text rendered by Graphics using Microsoft Sans Serif (66 points and up) loses the antialiasing effect of ClearType. You can use text-rendering hints to influence the antialiasing applied to Graphics-rendered text, but you fall out of the sphere of influence exerted by the shellwide font edge smoothing mode. If you need your customrendered text to conform to the current shell smoothing mode, TextRenderer is the more consistent option.

Performance

The performance of your output can be as important as how it eventually looks on your target device, particularly to screens, which often need to support high paint and refresh speeds. Because TextRenderer wraps GDI directly, it provides a higher-performance experience than using GDI+. For example, testing on the machine on which this chapter was typed demonstrated that text-rendering speeds for TextRenderer were approximately three times as fast as equivalent rendering by the Graphics object. Make sure you test appropriately if performance is an issue for your applications.

Integration with GDI+ Graphical Rendering

Often, rendering performance is a factor of rendering both textual and graphical output together. One benefit of rendering text using a Graphics object is the ability it gives you to integrate text output with the graphical capabilities of GDI+. A simple example that you've already seen is the ability to turn on antialiasing to ensure smoothly printed fonts; in this case, what was applied to the Graphics object was implicitly applied to the rendered text, along with all the other nontextual graphical output. Similarly, we cited a more complex example in which we used a GraphicsPath object to simulate an outline-only font. Unfortunately, this benefit isn't available using TextRenderer because it bypasses GDI+ and, by association, the capability of both Graphics and GraphicsPath objects to integrate with it.

Text-Formatting Comparison

Although both Graphics and TextRenderer offer a truckload of formatting options, if you use the StringFormat class and TextFormatFlags enumeration, respectively, a one-to-one parity does not exist, as outlined in Table 6.5.

Table 6.5. StringFormat Class Versus TextFormatFlags Enumeration

Member

StringFormat Class

TextFormatFlags Enumeration

 

Type and Value

Value

Alignment

StringAlignment.Near

Left (TextFormatFlag.Default)

 

StringAlignment.Center

HorizontalCenter

 

StringAlignment.Far

Right

DigitSubstitutionMethod

StringDigitSubstitute.User

No Equivalent

 

StringDigitSubstitute.None

No Equivalent

 

StringDigitSubstitute.National

No Equivalent

 

StringDigitSubstitute.Traditional

No Equivalent

FormatFlags

StringFormatFlags.DirectionRightToLeft

RightToLeft

 

StringFormatFlags.DirectionVertical

No Equivalent

 

StringFormatFlags.DisplayFormatControl

No Equivalent

 

StringFormatFlags.FitBlackBox

NoPadding

 

StringFormatFlags.LineLimit

WordBreak | TextBoxControl

 

StringFormatFlags.MeasureTrailingSpaces

No Equivalent

 

StringFormatFlags.NoClip

NoClipping

 

StringFormatFlags.NoFontFallback

No Equivalent

 

StringFormatFlags.NoWrap

SingleLine

 

Default Behavior

WordBreak

HotkeyPrefix

HotKeyPrefix.None

NoPrefix

 

HotKeyPrefix.Show

Default Behavior

 

HotKeyPrefix.Hide

HidePrefix

LineAlignment

StringAlignment.Near

Top (TextFormatFlag.Default)

 

StringAlignment.Center

VerticalCenter

 

StringAlignment.Far

Bottom

Trimming

StringTrimming.None

Default Behavior

 

StringTrimming.Character

No Equivalent

 

StringTrimming.Word

No Equivalent

 

StringTrimming.EllipsisCharacter

EndEllipsis

 

StringTrimming.EllipsisWord

WordEllipsis

 

StringTrimming.EllipsisPath

PathEllipsis

 

No Equivalent

GlyphOverhangPadding (TextFormatFlag.Default)

 

No Equivalent

ExternalLeading

 

No Equivalent

Internal

 

No Equivalent

ModifyString

 

No Equivalent

NoFullWidthCharacterBreak

 

No Equivalent

PrefixOnly

 

No Equivalent

PreserveGraphicsClipping

 

No Equivalent

PreserveGraphicsTranslateTransform

 

No Equivalent

LeftAndRightPadding

SetTabStops()

 

ExpandTabs

GetTabStops()

 

No Equivalent

SetDigitSubstitution()

 

No Equivalent

SetMeasurableCharacterRanges()

 

No Equivalent


One other feature notably missing from TextRenderer is text-rendering hints, because these are set via the Graphics object and thus have no effect on TextRenderer output.

Integration

Because of TextRenderer's ability to paint text that's consistent with the Windows shell and because it supports internationalization, TextRenderer is now responsible for handling text-rendering duties for several Windows Forms controls, including Button, Label, TextBox, RadioButton, and CheckBox.

However, this could be a problem if your application, overall, uses the Graphics text-rendering approach; there could be perceivable visual inconsistencies between the Windows Forms controls and your custom text-painting output. This is a likely scenario for all applications written for Windows Forms 1.x that you upgrade to Windows Forms 2.0.

Fortunately, those controls that do paint their text elements with TextRenderer come with a compatibility switch that you can use to determine which text-rendering technology to use. The switch is exposed from each of these controls as the Boolean UseCompatibleTextRendering property. By default, UseCompatibleTextRendering is set to false, indicating that TextRenderer should be used. You set it to true to ensure that these controls instead render text using Graphics, most easily from the Properties window, as shown in Figure 6.17.

Figure 6.17. Configuring a Control to Use Graphics Instead of TextRenderer


A nice benefit of setting UseCompatibleTextRendering from the Properties window is that you see the results immediately in the Windows Forms Designer. But if you have a lot of controls to change compatibility on, this approach could become tedious. Instead, you can invoke the Application.SetCompatibleTextRenderingDefault method to force all controls to use one model irrespective of the values of their own UseCompatibleTextRendering properties. By default, VS05 includes the call to SetCompatibleTextRenderingDefault in the wizard-generated Program.cs file:

// Program.cs static class Program {   /// <summary>   /// The main entry point for the application.   /// </summary>   [STAThread]   static void Main() {     Application.EnableVisualStyles();     // Make controls use TextRenderer     Application.SetCompatibleTextRenderingDefault(false);     Application.Run(new MainForm());   } }


As with UseCompatibleTextRendering, passing false to SetCompatibleTextRenderingDefault means that TextRenderer is used, and passing true ensures that Graphics is used.

If you're developing for Windows Forms 2.0 right off the bat, it's unlikely you'll need to fiddle with these settings unless you decide to use Graphics to render text in your applications or custom controls.




Windows Forms 2.0 Programming
Windows Forms 2.0 Programming (Microsoft .NET Development Series)
ISBN: 0321267966
EAN: 2147483647
Year: 2006
Pages: 216

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net