Label

A Label control, of the class System.Windows.Forms.Label, displays read-only text on a form. Text controls that provide read/write capability, such as the TextBox and RichTextBox, are described in Chapter 12.

Labels serve several different functions. At the most basic level, they display text on the client area of a form, such as titles, paragraphs, or captions for other controls. The text displayed by a Label is contained in its Text property. The Text property can be either hardcoded (set at design time) or dynamic (set programmatically at runtime).

Several examples presented in Chapter 7 dynamically control the size of a control (a button was used in the examples), based on the Text property of the control and the size of the font for that control. The Label control eases this chore with the AutoSize property. When set to true, the control is automatically resized to display the entire contents of the Text property.

In addition to the properties just mentioned, the Label control has many other properties, the most commonly used of which are listed in Table 11-1.

Table 11-1. Label properties

Property

Value type

Description

AutoSize

Boolean

Read/write. Value indicating that the label will automatically resize to display the entire Text property. Default is false. Using both PreferredWidth and PreferredHeight yields the same label size as AutoSize set to true.

BackgroundImage

Image

Read/write. The background image displayed on the label.

BorderStyle

BorderStyle

Read/write. The border style for the label. Values are members of the BorderStyle enumeration, listed in Table 11-2. The default value is BorderStyle.None.

FlatStyle

FlatStyle

Read/write. The flat style appearance of the label. Values are members of the FlatStyle enumeration, listed in Table 11-10. The default value is FlatStyle.Standard.

Image

Image

Read/write. The image displayed on the label. Cannot be used for the same control at the same time as the ImageList or ImageIndex properties.

ImageAlign

ContentAlignment

Read/write. Aligns image displayed in the label. Values are members of the ContentAlignment enumeration, listed in Table 11-3. The default value is ContentAlignment.MiddleCenter.

ImageIndex

Integer

Read/write. Zero-based index value of the Image object contained in the ImageList.

ImageList

ImageList

Read/write. The image list that contains the images displayed in the label control. One image is displayed at a time, selected by the ImageIndex property. The ImageList stores a collection of Image objects.

The ImageList component is described fully in Chapter 7.

PreferredHeight

Integer

Read-only. Returns the height of the label, in pixels, if a single line of text were displayed. The value returned reflects the current font for the label.

PreferredWidth

Integer

Read-only. Returns the width of the label, in pixels, if a single line of text were displayed, assuming no line wrapping. The returned value reflects the current font for the label.

TextAlign

ContentAlignment

Read/write. Aligns text displayed in the label. Values are members of the ContentAlignment enumeration, listed in Table 11-3. The default value is ContentAlignment.TopLeft.

UseMnemonic

Boolean

Read/write. Value indicating if an ampersand (&) character in the label's Text property will be interpreted as an access key character. If true (the default), the user can move focus to the control following in the tab order by pressing the Alt key in combination with the access key.

Table 11-2. BorderStyle enumeration values

Value

Description

Fixed3D

3-D border.

FixedSingle

Single-line border.

None

No border.

Table 11-3. ContentAlignment enumeration values

Value

Vertical alignment

Horizontal alignment

BottomCenter

Bottom

Center

BottomLeft

Bottom

Left

BottomRight

Bottom

Right

MiddleCenter

Middle

Center

MiddleLeft

Middle

Left

MiddleRight

Middle

Right

TopCenter

Top

Center

TopLeft

Top

Left

TopRight

Top

Right

11.1.1 Using labels to provide access keys

A Label control also helps provide keyboard navigation through the use of access keys. An access key lets you press, for example, Alt-A to go to a control, such as a button, with an underlined A on it. Using a label to create an access key is useful when you need to navigate to a control, such as text box, that does not provide its own access key.

To create an access key, add a Label control to the form, setting its Text property with an ampersand (&) in front of the character to be used as the access key. Set the UseMnemonic property of the Label to true (the default value). Create the target control to which the access key should send focus to, such as a text box. Now set the TabIndex property of Label and its associated target control so that the TabIndex of the target control is one greater than the TabIndex of the Label. This latter step can be done by either setting the TabIndex properties explicitly or creating and adding the Label control to the Controls collection first, immediately followed by the target control.

When the user presses the Alt key in combination with the key after the ampersand, focus will shift to the target control. Example 11-1 and Example 11-2 will demonstrate this concept.

Many of the examples used in the book so far have included Label controls; they are rather ubiquitous. The program listed in Example 11-1 (in C#) and Example 11-2 (in VB.NET) demonstrates many of the common uses and properties of labels, borrowing several techniques from previous examples. In these examples, a form is created with three different labels: one is a caption to a TextBox (which gathers user input), the second dynamically displays the contents of that TextBox, and the third displays an image. Also, a set of RadioButtons change the font style of Label, echoing the contents of the TextBox. (Radio buttons are discussed later in this chapter.)

Example 11-1. Label demonstration in C# (labels.cs)

using System; using System.Drawing; using System.Windows.Forms; namespace ProgrammingWinApps { public class Labels : Form { Label lblEcho; TextBox txt; public Labels( ) { Text = "Labels"; Size = new Size(300,250); lblEcho = new Label( ); lblEcho.Parent = this; lblEcho.Text = "The quick brown fox..."; lblEcho.Location = new Point(0,0); lblEcho.AutoSize = true; lblEcho.BorderStyle = BorderStyle.Fixed3D; int yDelta = lblEcho.Height + 10; Image img = Image.FromFile( @"C:Program FilesMicrosoft Visual Studio .NET 2003Common7" + @"Graphicsitmapsassortedhappy.bmp"); Label lblImage = new Label( ); lblImage.Parent = this; lblImage.Location = new Point(250, 0); lblImage.Image = img; lblImage.Anchor = AnchorStyles.Top | AnchorStyles.Right; lblImage.Size = new Size(img.Width, img.Height); Label lblCaption = new Label( ); lblCaption.Parent = this; lblCaption.Text = "&Enter Text Here:"; lblCaption.Size = new Size(lblCaption.PreferredWidth, lblCaption.PreferredHeight); lblCaption.Location = new Point(0, yDelta); // Commented out so border will not hide the underscore // lblCaption.BorderStyle = BorderStyle.FixedSingle; txt = new TextBox( ); txt.Parent = this; txt.Size = new Size(100,23); txt.Location = new Point(lblCaption.Width + 5, yDelta); txt.TextChanged += new System.EventHandler(txt_TextChanged); FontStyle theEnum = new FontStyle( ); FontStyle[ ] theStyles = (FontStyle[ ])Enum.GetValues(theEnum.GetType( )); int i = 1; foreach (FontStyle style in theStyles) { RadioButton rdo = new RadioButton( ); rdo.Parent = this; rdo.Location = new Point(25, yDelta * (i + 1)); rdo.Size = new Size(75,20); rdo.Text = style.ToString( ); rdo.Tag = style; rdo.CheckedChanged += new System.EventHandler(rdo_CheckedChanged); if (rdo.Text = = "Regular") rdo.Checked = true; i++; } } static void Main( ) { Application.Run(new Labels( )); } private void txt_TextChanged(object sender, EventArgs e) { lblEcho.Text = txt.Text; } private void rdo_CheckedChanged(object sender, EventArgs e) { RadioButton rdo = (RadioButton)sender; FontStyle fs = (FontStyle)rdo.Tag; lblEcho.Font = new Font(lblEcho.Font, fs); } } }

Example 11-2. Label demonstration in VB.NET (labels.vb)

Option Strict On imports System imports System.Drawing imports System.Windows.Forms namespace ProgrammingWinApps public class Labels : inherits Form dim lblEcho as Label dim txt as TextBox public sub New( ) Text = "Labels" Size = new Size(300,250) lblEcho = new Label( ) lblEcho.Parent = me lblEcho.Text = "The quick brown fox..." lblEcho.Location = new Point(0,0) lblEcho.AutoSize = true lblEcho.BorderStyle = BorderStyle.Fixed3D dim yDelta as integer = lblEcho.Height + 10 dim img as Image = Image.FromFile( _ "C:\Program Files\Microsoft Visual Studio .NET 2003\" + _ "Common7\Graphics\bitmaps\assorted\happy.bmp") dim lblImage as Label = new Label( ) lblImage.Parent = me lblImage.Location = new Point(250, 0) lblImage.Image = img lblImage.Anchor = AnchorStyles.Top or AnchorStyles.Right lblImage.Size = new Size(img.Width, img.Height) dim lblCaption as Label = new Label( ) lblCaption.Parent = me lblCaption.Text = "&Enter Text Here:" lblCaption.Size = new Size(lblCaption.PreferredWidth, _ lblCaption.PreferredHeight) lblCaption.Location = new Point(0, yDelta) ' Commented out so border will not hide the underscore ' lblCaption.BorderStyle = BorderStyle.FixedSingle txt = new TextBox( ) txt.Parent = me txt.Size = new Size(100,23) txt.Location = new Point(lblCaption.Width + 5, yDelta) AddHandler txt.TextChanged, AddressOf txt_TextChanged dim theEnum as new FontStyle( ) dim theStyles as FontStyle( ) = CType([Enum].GetValues( _ theEnum.GetType( )), FontStyle( )) dim i as integer = 1 dim style as FontStyle for each style in theStyles dim rdo as RadioButton = new RadioButton( ) rdo.Parent = me rdo.Location = new Point(25, yDelta * (i + 1)) rdo.Size = new Size(75,20) rdo.Text = style.ToString( ) rdo.Tag = style AddHandler rdo.CheckedChanged, AddressOf rdo_CheckedChanged if rdo.Text = "Regular" then rdo.Checked = true end if i = i + 1 next end sub public shared sub Main( ) Application.Run(new Labels( )) end sub private sub txt_TextChanged(ByVal sender as object, _ ByVal e as EventArgs) lblEcho.Text = txt.Text end sub private sub rdo_CheckedChanged(ByVal sender as object, _ ByVal e as EventArgs) dim rdo as RadioButton = CType(sender, RadioButton) dim fs as FontStyle = CType(rdo.Tag, FontStyle) lblEcho.Font = new Font(lblEcho.Font, fs) end sub end class end namespace

When either program is compiled and run, you get the form shown in Figure 11-1. After entering some text in the TextBox and changing the font style to bold, the form will look like Figure 11-2.

Figure 11-1. Labels program on startup

Figure 11-2. Labels program after entering text and changing font style

The first label created in the constructor of the form, lblEcho, echoes the text entered in the TextBox. It and the Textbox are declared as form member variables, and thus can be accessed from any method of the Form class:

Label lblEcho; TextBox txt;

dim lblEcho as Label dim txt as TextBox

lblEcho is instantiated in the constructor and its properties are set:

lblEcho.Parent = this; lblEcho.Text = "The quick brown fox..."; lblEcho.Location = new Point(0,0); lblEcho.AutoSize = true; lblEcho.BorderStyle = BorderStyle.Fixed3D; int yDelta = lblEcho.Height + 10;

lblEcho.Parent = me lblEcho.Text = "The quick brown fox..." lblEcho.Location = new Point(0,0) lblEcho.AutoSize = true lblEcho.BorderStyle = BorderStyle.Fixed3D dim yDelta as integer = lblEcho.Height + 10

As with all controls, setting the parent property adds the control to the parent control's Controls collection. The Text and Location properties are typical of all controls.

The AutoSize property is set to true, which causes the label to resize itself automatically as its contents changes in length. The BorderStyle property is set to one of the values of the BorderStyle enumeration listed in Table 11-2.

An integer variable, yDelta, is declared and calculated based on the height of lblEcho. This variable will be used later in the program to calculate the vertical position of the other controls.

The next control to be created is lblImage, whose sole purpose here is to display an image. The Image object is created using the FromFile static method of the Image class. The file containing the image used here is hardcoded; it is one of many images that ship with Visual Studio .NET:

Image img = Image.FromFile( @"C:Program FilesMicrosoft Visual Studio .NET 2003Common7" + @"Graphicsitmapsassortedhappy.bmp");

dim img as Image = Image.FromFile( _ "C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\" + _ "Graphics\bitmaps\assorted\happy.bmp")

Notice how a literal string (using the @ sign) is used in the C# version to eliminate the requirement of escaping the backslash characters with a second backslash. This feature is not supported in VB.NET.

The Image property is then set to that Image object:

lblImage.Image = img

The Anchor property is set to a bitwise combination of Top and Right. This keeps the location of the control constant relative to the top and right edges of the form, even if the form is resized by the user. (Anchoring was covered in Chapter 7.)

The Size property of the control is set based on the Width and Height of the Image object it contains.

lblImage.Size = new Size(img.Width, img.Height)

The next control to be declared, instantiated, and have its properties set is lblCaption, a Label control used as a caption for the TextBox that will be created shortly. Notice that the Text property has an ampersand character in front of the letter E. This will cause that letter E to be underlined when the form is displayed, indicating that it is an access key.

lblCaption.Text = "&Enter Text Here:"

When the user presses Alt + E, focus will move to the control immediately following the label in the tab order. In this case, the control would be the TextBox, since it is added to the Controls collection immediately after lblCaption.

If you need to include an ampersand as part of the displayed text, use a second ampersand character to escape the first. For example, if the text to be displayed in a label is Cut & Paste, use the following line of code:

lblCaption.Text = "&Cut && Paste"

The Size property is set using the PreferredWidth and PreferredHeight properties of the Label control for the width and height, respectively.

lblCaption.Size = new Size(lblCaption.PreferredWidth, _ lblCaption.PreferredHeight)

The Location property uses the yDelta variable calculated earlier for its vertical offset from the upper edge of the form client area.

lblCaption.Location = new Point(0, yDelta)

The BorderStyle property of lblCaption is set to FixedSingle, but commented out. Uncommenting this line of code will show the size of the label clearly and demonstrate what this border looks like. However, it will also hide the underscore character beneath the access key, although the access key will still work as expected.

A TextBox called txt is created next. Chapter 12 will cover TextBoxes in detail. For now, note that the Location property uses the width of lblCaption and the previously calculated value yDelta to correctly place the control relative to the other controls, and an event handler is created to handle the TextChanged event. This latter feature will cause the contents of the TextBox to be echoed by lblEcho:

txt.Location = new Point(lblCaption.Width + 5, yDelta); txt.TextChanged += new System.EventHandler(txt_TextChanged);

txt.Location = new Point(lblCaption.Width + 5, yDelta) AddHandler txt.TextChanged, AddressOf txt_TextChanged

The event handler method itself is very simple, containing a single line of code that assigns the Text property of the TextBox to the Text property of lblEcho.

lblEcho.Text = txt.Text

The next section of code is similar to the examples from Chapter 7 that demonstrated the use of the Tag property. In this example, an array of FontStyles is created from the FontStyle enumeration:

FontStyle theEnum = new FontStyle( ); FontStyle[ ] theStyles = (FontStyle[ ])Enum.GetValues(theEnum.GetType( ));

dim theEnum as new FontStyle( ) dim theStyles as FontStyle( ) = CType([Enum].GetValues( _ theEnum.GetType( )), FontStyle( ))

This array is then looped through using a foreach (For Each in VB.NET) loop, creating a RadioButton for each member of the enumeration.

You converted the enumeration to an array so you could call foreach on that array. You can iterate through an array, but not through an enumeration.

When the RadioButton is changed, the CheckedChanged event is fired, which is handled by the rdo_CheckedChanged method. This loop and event handler is very similar to Example 7-13 and Example 7-14, so the analysis will not be repeated here.

Pay attention to how the FontStyle of the lblEcho label is changed.

lblEcho.Font = new Font(lblEcho.Font, fs)

The Font.Style property is read-only. In fact, since the Font object is immutable (all of its properties are read-only), the only way to change a Font property is to assign a new Font object based on the existing Font. The Font object has over a dozen different overloaded constructors, which are covered in Chapter 9. The one used here takes an existing Font object as a prototype from which to create the new Font object and a member of the FontStyle enumeration to apply to the new Font.

11.1.2 LinkLabel

Closely related to and derived from the Label control is the LinkLabel control, of the class System.Windows.Forms.LinkLabel, which displays one or more hyperlinks. In addition to the properties and features discussed above for the Label control, the LinkLabel has the properties listed in Table 11-4.

The LinkLabel control does not automatically provide actual linkage to anything, nor, by default, does it change the color of the link once it has been visited, as is done in most browsers. It is easy to add these features, however, with the properties and events of the LinkLabel class, as demonstrated next.

Table 11-4. LinkLabel properties

Property

Value type

Description

ActiveLinkColor

Color

Read/write. The color to display an active link. A link is active while it is clicked. The default color is specified by the system, typically Color.Red.

DisabledLinkColor

Color

Read/write. The color to display a disabled link. Disabled links do not raise the LinkClicked event.

LinkArea

LinkArea

Read/write. The area within the LinkLabel control that represents a hyperlink.

The Start property of the LinkArea structure is the zero-based index of the character in the LinkLabel Text property representing the start of the link.

The Length property of the LinkArea structure is the number of characters, including the starting character, comprising the link.

LinkBehavior

LinkBehavior

Read/write. The behavior of the link. The values must be a member of the LinkBehavior enumeration, listed in Table 11-5.

LinkColor

Color

Read/write. The color to display a normal link. The default color is specified by the system, typically Color.Blue.

Links

LinkLabel.LinkCollection

Read-only. Returns the collection of links contained within the LinkLabel.

LinkVisited

Boolean

Read/write. Value indicating if the link should display as though it were visited. Default is false. Does not automatically get set to true; this must be done by code in the LinkClicked event handler.

Only applies to the first link defined for the control. Use the Visited property of the LinkLabel.Link class for multiple links in a control.

VisitedLinkColor

Color

Read/write. The color to display a link that has been visited previously. The default color is specified by the system, typically Color.Purple.

Table 11-5. LinkBehavior enumeration values

Value

Description

AlwaysUnderline

The link is always displayed with underlined text.

HoverUnderline

The link is displayed with underlined text only when the mouse is hovering over the link.

NeverUnderline

The link text is never underlined. It can be distinguished by using the LinkColor property.

SystemDefault

The link is displayed using the system default.

When a LinkLabel control is clicked, it raises an event called LinkClicked, which has an event argument of type LinkLabelLinkClickedEventArgs. This event argument exposes a single read-only property called Link, which returns the link that was clicked. Several different ways of handling this event will be demonstrated in Example 11-3 (using C#) and Example 11-4 (using VB.NET).

A Links property of the LinkLabel, listed in Table 11-4, is of type LinkLabel.LinkCollection, a sub-class of LinkLabel. This is a collection of all the links contained by the LinkLabel control. As a class in its own right, it exposes several useful properties (listed in Table 11-6) and methods (listed in Table 11-7).

Table 11-6. LinkLabel.LinkCollection properties

Property

Value type

Description

Count

Integer

Read-only property that returns the number of links in the collection.

Item

LinkLabel.Link

Read/write. The link at the specified index.

Table 11-7. LinkLabel.LinkCollection methods

Method

Description

Add

Adds a link to the collection. Overloaded.

Clear

Removes all the links from the collection.

Contains

Returns true if the specified link is contained in the collection.

GetEnumerator

Returns an enumerator used to iterate through the collection.

IndexOf

Returns index of the specified link in the collection.

Remove

Removes the specified link from the collection.

RemoveAt

Removes the link with the specified zero-based index from the collection.

Each link within a LinkLabel control is represented by a member of the LinkLabel.Link class. Each Link has the properties listed in Table 11-8.

Table 11-8. LinkLabel.Link properties

Property

Value type

Description

Enabled

Boolean

Read/write. Value indicating if the link is enabled. If disabled, then clicking on the link does not raise the LinkClicked event, and the link will appear in the color specified by the DisabledLinkColor property.

Length

Integer

Read/write. The number of characters in the link text.

LinkData

Object

Read/write. Data associated with the link.

Start

Integer

Read/write. The zero-based starting location of the link within the Text of the LinkLabel.

Visited

Boolean

Read/write. The value indicating whether the link should display as though it were visited. Default is false. Does not automatically get set to true; this must be done by code in the LinkClicked event handler.

Used for multiple links in a control.

Example 11-3 (in C#) and Example 11-4 (in VB.NET) demonstrate many features of the LinkLabel control. These examples show five different LinkLabel controls, each configured differently. The first three LinkLabels are single links to web pages, the next is a LinkLabel containing four different links, and the last links to a text file that automatically opens up Notepad (or whichever application on the user system is the default application for files with a .txt extension). A full analysis follows the code listings.

Example 11-3. LinkLabels in C# (LinkLabels.cs)

using System; using System.Drawing; using System.Windows.Forms; namespace ProgrammingWinApps { public class LinkLabels : Form { LinkLabel lnkMsft; LinkLabel lnkLA; public LinkLabels( ) { Text = "LinkLabels"; Size = new Size(300,250); // use Text property & LinkArea lnkMsft = new LinkLabel( ); lnkMsft.Parent = this; lnkMsft.Text = "www.microsoft.com"; lnkMsft.Location = new Point(0,0); lnkMsft.AutoSize = true; lnkMsft.BorderStyle = BorderStyle.None; lnkMsft.LinkArea = new LinkArea(4,9); lnkMsft.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler( lnkMsft_LinkClicked); // use Add lnkLA = new LinkLabel( ); lnkLA.Parent = this; lnkLA.Text = "Liberty Associates"; lnkLA.Location = new Point(0,25); lnkLA.AutoSize = true; lnkLA.BorderStyle = BorderStyle.None; lnkLA.Links.Add(0,7,"www.LibertyAssociates.com"); lnkLA.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler( lnkLA_LinkClicked); // use generic Add & generic handler LinkLabel lnkSterSol = new LinkLabel( ); lnkSterSol.Parent = this; lnkSterSol.Text = "Sterling Solutions"; lnkSterSol.Location = new Point(0,50); lnkSterSol.AutoSize = true; lnkSterSol.BorderStyle = BorderStyle.None; lnkSterSol.Links.Add(0,lnkSterSol.Text.ToString( ).Length, "www.SterSol.com"); lnkSterSol.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler( lnkGeneric_LinkClicked); // multiple links & generic handler LinkLabel lnkMulti = new LinkLabel( ); lnkMulti.Parent = this; lnkMulti.Text = "Ford Chevy VW Porsche"; lnkMulti.Location = new Point(0,75); lnkMulti.AutoSize = true; lnkMulti.BorderStyle = BorderStyle.None; lnkMulti.LinkBehavior = LinkBehavior.HoverUnderline; lnkMulti.Links.Add(0,4,"www.Ford.com"); lnkMulti.Links.Add(6,5,"www.chevrolet.com"); lnkMulti.Links.Add(13,2, "www.vw.com"); lnkMulti.Links.Add(17,7,"www.porsche.com"); lnkMulti.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler( lnkGeneric_LinkClicked); // link to text file LinkLabel lnkTxtFile = new LinkLabel( ); lnkTxtFile.Parent = this; lnkTxtFile.Text = "Gettysburg Address"; lnkTxtFile.Location = new Point(0,100); lnkTxtFile.AutoSize = true; lnkTxtFile.BorderStyle = BorderStyle.None; lnkTxtFile.LinkBehavior = LinkBehavior.NeverUnderline; lnkTxtFile.ActiveLinkColor = Color.Green; lnkTxtFile.LinkColor = Color.Red; lnkTxtFile.VisitedLinkColor = Color.Orange; lnkTxtFile.Links.Add(0,lnkTxtFile.Text.ToString( ).Length, @"c:GettysburgAddress.txt"); lnkTxtFile.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler( lnkGeneric_LinkClicked); } static void Main( ) { Application.Run(new LinkLabels( )); } private void lnkMsft_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { lnkMsft.Links[lnkMsft.Links.IndexOf(e.Link)].Visited = true; System.Diagnostics.Process.Start(lnkMsft.Text); } private void lnkLA_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { lnkLA.LinkVisited = true; System.Diagnostics.Process.Start(e.Link.LinkData.ToString( )); } private void lnkGeneric_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { LinkLabel lnk = new LinkLabel( ); lnk = (LinkLabel)sender; lnk.Links[lnk.Links.IndexOf(e.Link)].Visited = true; System.Diagnostics.Process.Start(e.Link.LinkData.ToString( )); } } }

Example 11-4. LinkLabels in VB.NET (LinkLabels.vb)

Option Strict On imports System imports System.Drawing imports System.Windows.Forms namespace ProgrammingWinApps public class LinkLabels : inherits Form dim lnkMsft as LinkLabel dim lnkLA as LinkLabel public sub New( ) Text = "LinkLabels" Size = new Size(300,250) ' use Text property & LinkArea lnkMsft = new LinkLabel( ) lnkMsft.Parent = me lnkMsft.Text = "www.microsoft.com" lnkMsft.Location = new Point(0,0) lnkMsft.AutoSize = true lnkMsft.BorderStyle = BorderStyle.None lnkMsft.LinkArea = new LinkArea(4,9) AddHandler lnkMsft.LinkClicked, AddressOf lnkMsft_LinkClicked ' use Add lnkLA = new LinkLabel( ) lnkLA.Parent = me lnkLA.Text = "Liberty Associates" lnkLA.Location = new Point(0,25) lnkLA.AutoSize = true lnkLA.BorderStyle = BorderStyle.None lnkLA.Links.Add(0,7,"www.LibertyAssociates.com") AddHandler lnkLA.LinkClicked, AddressOf lnkLA_LinkClicked ' use generic Add & generic handler dim lnkSterSol as LinkLabel = new LinkLabel( ) lnkSterSol.Parent = me lnkSterSol.Text = "Sterling Solutions" lnkSterSol.Location = new Point(0,50) lnkSterSol.AutoSize = true lnkSterSol.BorderStyle = BorderStyle.None lnkSterSol.Links.Add(0,lnkSterSol.Text.ToString( ).Length, _ "www.SterSol.com") AddHandler lnkSterSol.LinkClicked, _ AddressOf lnkGeneric_LinkClicked ' multiple links & generic handler dim lnkMulti as LinkLabel = new LinkLabel( ) lnkMulti.Parent = me lnkMulti.Text = "Ford Chevy VW Porsche" lnkMulti.Location = new Point(0,75) lnkMulti.AutoSize = true lnkMulti.BorderStyle = BorderStyle.None lnkMulti.LinkBehavior = LinkBehavior.HoverUnderline lnkMulti.Links.Add(0,4,"www.Ford.com") lnkMulti.Links.Add(6,5,"www.chevrolet.com") lnkMulti.Links.Add(13,2, "www.vw.com") lnkMulti.Links.Add(17,7,"www.porsche.com") AddHandler lnkMulti.LinkClicked, AddressOf lnkGeneric_LinkClicked ' link to text file dim lnkTxtFile as LinkLabel = new LinkLabel( ) lnkTxtFile.Parent = me lnkTxtFile.Text = "Gettysburg Address" lnkTxtFile.Location = new Point(0,100) lnkTxtFile.AutoSize = true lnkTxtFile.BorderStyle = BorderStyle.None lnkTxtFile.LinkBehavior = LinkBehavior.NeverUnderline lnkTxtFile.ActiveLinkColor = Color.Green lnkTxtFile.LinkColor = Color.Red lnkTxtFile.VisitedLinkColor = Color.Orange lnkTxtFile.Links.Add(0,lnkTxtFile.Text.ToString( ).Length, _ "c:\GettysburgAddress.txt") AddHandler lnkTxtFile.LinkClicked, _ AddressOf lnkGeneric_LinkClicked end sub public shared sub Main( ) Application.Run(new LinkLabels( )) end sub private sub lnkMsft_LinkClicked(ByVal sender as object, _ ByVal e as LinkLabelLinkClickedEventArgs) lnkMsft.Links(lnkMsft.Links.IndexOf(e.Link)).Visited = true System.Diagnostics.Process.Start(lnkMsft.Text) end sub private sub lnkLA_LinkClicked(ByVal sender as object, _ ByVal e as LinkLabelLinkClickedEventArgs) lnkLA.LinkVisited = true System.Diagnostics.Process.Start(e.Link.LinkData.ToString( )) end sub private sub lnkGeneric_LinkClicked(ByVal sender as object, _ ByVal e as LinkLabelLinkClickedEventArgs) dim lnk as LinkLabel = new LinkLabel( ) lnk = CType(sender, LinkLabel) lnk.Links(lnk.Links.IndexOf(e.Link)).Visited = true System.Diagnostics.Process.Start(e.Link.LinkData.ToString( )) end sub end class end namespace

When either program is compiled and run, you will get the form shown in Figure 11-3. Although you can't see it in this monochrome image, on the user's screen the underlined links are blue, as is the line showing the four automobile brands, and the Gettysburg Address line is red.

Figure 11-3. LinkLabels

The LinkLabels program starts by declaring two LinkLabel controls as form member variables. These two controls need to be declared this way because they are referenced outside the constructor; the other controls are never referenced outside the constructor and can be local to the constructor method.

LinkLabel lnkMsft; LinkLabel lnkLA;

dim lnkMsft as LinkLabel dim lnkLA as LinkLabel

The first LinkLabel control to be created, lnkMsft, provides a link to the Microsoft web site. As shown in Figure 11-3, the Text property of the control is the full URL of the web site, but the actual link is comprised only of the word Microsoft. The implementation technique used here dictates that the full URL be used in the Text property, but you can limit the characters comprising the actual link. The code used to implement this LinkLabel in C# follows:

lnkMsft = new LinkLabel( ); lnkMsft.Parent = this; lnkMsft.Text = "www.microsoft.com"; lnkMsft.Location = new Point(0,0); lnkMsft.AutoSize = true; lnkMsft.BorderStyle = BorderStyle.None; lnkMsft.LinkArea = new LinkArea(4,9); lnkMsft.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler( lnkMsft_LinkClicked);

The VB.NET code is exactly the same, except for the trailing semicolons and the highlighted lines at the end of the snippet that add the event handler method to the LinkClicked event delegate. The VB.NET equivalent for adding the handler to the delegate is as follows:

AddHandler lnkMsft.LinkClicked, AddressOf lnkMsft_LinkClicked

In this code snippet, all the lines of code are similar to those used for a normal Label control except for the last two statements.

The LinkArea property specifies which characters in the Text property comprise the actual link. The first argument specifies the starting character, zero-based, and the second argument specifies the number of characters, including the starting character, to include in the link.

This control has its own event handler method. (As you will see shortly, some of the LinkLabel controls on this form use a generic event handler.) The event handler method is reproduced here:

private void lnkMsft_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { lnkMsft.Links[lnkMsft.Links.IndexOf(e.Link)].Visited = true; System.Diagnostics.Process.Start(lnkMsft.Text); }

private sub lnkMsft_LinkClicked(ByVal sender as object, _ ByVal e as LinkLabelLinkClickedEventArgs) lnkMsft.Links(lnkMsft.Links.IndexOf(e.Link)).Visited = true System.Diagnostics.Process.Start(lnkMsft.Text) end sub

The event argument, of type LinkLabelLinkClickedEventArgs, exposes the link that raised the event in the Link property as e.Link. That property is nested in the first line of code in the method to find the index of the link in the Links collection. This index is then used to set the Visited property of that LinkLabel.Link to true. This has the effect of changing the color of the link to the VisitedLinkColor. Since the VisitedLinkColor property is not set for this control, it defaults to purple.

The second line in the method invokes a static form of the System.Diagnostics.Process.Start method. This method takes a filename (at the minimum), and starts the default application associated with files with that file extension. Notice that in this method, the passed filename in is the Text property of the control. (It is also possible to pass in a filename that is not displayed as the Text property of the control, as you will see on the other LinkLabels in this example.) Since the filename passed in is actually a URL, the default application that runs is a web browser.

The next LinkLabel control on the form, lnkLA, displays a link to www.LibertyAssociates.com. This is similar to the Microsoft link, except it adds a link to the Links collection rather than specifying the LinkArea property. This is done with the following lines of code:

lnkLA.Text = "Liberty Associates"; lnkLA.Links.Add(0,7,"www.LibertyAssociates.com")

The Add method takes three arguments. The first two are the same as for LinkAreathe zero-based starting character and the length of the link. The third argument is the URL it links to. Notice that this LinkLabel displays one text string, specified in the Text property for the control, but links to a URL different from that text string, specified in the Links property.

This LinkLabel control also has its own two-line event handler for the LinkClicked event, reproduced here:

private void lnkLA_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { lnkLA.LinkVisited = true; System.Diagnostics.Process.Start(e.Link.LinkData.ToString( )); }

private sub lnkLA_LinkClicked(ByVal sender as object, _ ByVal e as LinkLabelLinkClickedEventArgs) lnkLA.LinkVisited = true System.Diagnostics.Process.Start(e.Link.LinkData.ToString( )) end sub

Similar to the previous event handler, the first line sets the LinkVisited property to true so it will display with the color specified by the VisitedLinkColor (which is not set for this control, so it defaults to purple). The LinkVisited property should be used only for a LinkLabel that has a single link. The Microsoft LinkLabel could have also used the simpler LinkVisited property rather than indexing into the Links collection and setting the Visited property; in this case they are equivalent. You will encounter a situation in which the indexing syntax is required shortly.

The Liberty Associates LinkLabel links to the URL specified previously in the Add method.

System.Diagnostics.Process.Start(e.Link.LinkData.ToString( ))

Here, the LinkData property of the Link contains the URL. It is converted to a string, using the ToString method, which is given to the Start method. Again, since this is a valid URL, a browser will be invoked.

The next LinkLabel control on the form, lnkSterSol, displays a hyperlink to www.SterSol.com. This is similar to the Liberty Associates hyperlink, with two changes. First, the Add method uses a dynamic calculation of the length of the Text property to specify the length of the linked characters.

lnkSterSol.Links.Add(0,lnkSterSol.Text.ToString( ).Length, _ "www.SterSol.com")

This calculation ensures that the entire Text property displays as a link without having to count the characters manually and hardcode the literal number in the arguments.

The second change is a move to a generic event handler, one that can be used with any number of LinkLabel controls. The line that adds this generic event handler to the LinkClicked event delegate is as follows:

lnkSterSol.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler( lnkGeneric_LinkClicked);

AddHandler lnkSterSol.LinkClicked, AddressOf lnkGeneric_LinkClicked

The generic event handler method is called lnkGeneric_LinkClicked. It is reproduced here:

private void lnkGeneric_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { LinkLabel lnk = new LinkLabel( ); lnk = (LinkLabel)sender; lnk.Links[lnk.Links.IndexOf(e.Link)].Visited = true; System.Diagnostics.Process.Start(e.Link.LinkData.ToString( )); }

private sub lnkGeneric_LinkClicked(ByVal sender as object, _ ByVal e as LinkLabelLinkClickedEventArgs) dim lnk as LinkLabel = new LinkLabel( ) lnk = CType(sender, LinkLabel) lnk.Links(lnk.Links.IndexOf(e.Link)).Visited = true System.Diagnostics.Process.Start(e.Link.LinkData.ToString( )) end sub

The first two lines in the method declare a LinkLabel variable, lnk, and instantiate it with the object, called sender, which raised the event. That object is cast to type LinkLabel in the second line in the method. Then the Visited property of the Link in the Links collection is set to true, as was done for the Microsoft event handler. Finally, the static Process.Start method is called, as was done for the Liberty Associates event handler.

The next LinkLabel on the form demonstrates a control with multiple links in a single control. The Text property contains the text to display for four different links, and four separate Add statements, each of which specifies a starting character, the number of characters in the link, and the URL to which it links.

lnkMulti.Text = "Ford Chevy VW Porsche" lnkMulti.LinkBehavior = LinkBehavior.HoverUnderline lnkMulti.Links.Add(0,4,"www.Ford.com") lnkMulti.Links.Add(6,5,"www.chevrolet.com") lnkMulti.Links.Add(13,2, "www.vw.com") lnkMulti.Links.Add(17,7,"www.porsche.com")

This LinkLabel control also demonstrates the use of the LinkBehavior property, which is why these links did not display as underlined back in Figure 11-3. They do display as underlined when the mouse hovers over each individual link.

The lnkMulti control uses the generic LinkClicked event handler, which uses the indexed Visited property rather than the unitary LinkVisited property. Consequently, each individual link correctly displays if it has been visited. If you had substituted the following line into the generic event handler:

lnk.LinkVisited = true

then the first link in the collection, such as Ford, would have displayed as visited irrespective of which of the four links was actually clicked.

The final LinkLabel control in the application links to a file on the local hard drive rather than a URL. In this case, a text file contains Lincoln's Gettysburg Address, located in the root of Drive C. The generic event handler is again used. Since the filename has an extension of .txt, the default application for that extension is used to open it (typically, Notepad).

If Gettysburg.txt is missing from your hard drive, clicking on this link will throw a file not found exception.

This LinkLabel also sets several of the display properties that change the default colors and behavior of the link. The lines of code that create the control are reproduced here:

LinkLabel lnkTxtFile = new LinkLabel( ); lnkTxtFile.Parent = this; lnkTxtFile.Text = "Gettysburg Address"; lnkTxtFile.Location = new Point(0,100); lnkTxtFile.AutoSize = true; lnkTxtFile.BorderStyle = BorderStyle.None; lnkTxtFile.LinkBehavior = LinkBehavior.NeverUnderline; lnkTxtFile.ActiveLinkColor = Color.Green; lnkTxtFile.LinkColor = Color.Red; lnkTxtFile.VisitedLinkColor = Color.Orange; lnkTxtFile.Links.Add(0,lnkTxtFile.Text.ToString( ).Length, @"c:GettysburgAddress.txt"); lnkTxtFile.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler( lnkGeneric_LinkClicked);

dim lnkTxtFile as LinkLabel = new LinkLabel( ) lnkTxtFile.Parent = me lnkTxtFile.Text = "Gettysburg Address" lnkTxtFile.Location = new Point(0,100) lnkTxtFile.AutoSize = true lnkTxtFile.BorderStyle = BorderStyle.None lnkTxtFile.LinkBehavior = LinkBehavior.NeverUnderline lnkTxtFile.ActiveLinkColor = Color.Green lnkTxtFile.LinkColor = Color.Red lnkTxtFile.VisitedLinkColor = Color.Orange lnkTxtFile.Links.Add(0,lnkTxtFile.Text.ToString( ).Length, _ "c:\GettysburgAddress.txt") AddHandler lnkTxtFile.LinkClicked, AddressOf lnkGeneric_LinkClicked

The LinkVisited and Visited properties are reset every time the application is run, unlike the default behavior of most browsers. If you want those properties to persist from one program execution to the next, you must save the information somewhere, such as in an XML configuration file.

Категории