Button Classes

If labels are the most common control in Windows applications, then buttons must be a close second. A command button tells the application to take some action. In the .NET Framework, the Button control is an instance of the System.Windows.Forms.Button class. It, along with the CheckBox and RadioButton controls, are derived from the ButtonBase class, as shown in Figure 11-4. The CheckBox and RadioButton controls are covered in the next section.

Figure 11-4. Button class hierarchy

figs/pnwa_1104.gif

The ButtonBase class has several commonly used properties listed in Table 11-9, in addition to those inherited from Control. The ImageList and ImageIndex properties were demonstrated in Section 7.1.2.15. Other common ButtonBase properties will be demonstrated with a Button control in Example 11-5 and Example 11-6.

Table 11-9. ButtonBase properties

Property

Value type

Description

FlatStyle

FlatStyle

Read/write. The flat-style appearance of the control. Valid values must be a member of the FlatStyle enumeration, listed in Table 11-10. The default value is FlatStyle.Standard.

Image

Image

Read/write. The image displayed on the control. 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 containing the images displayed in the 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.

TextAlign

ContentAlignment

Aligns text displayed in the control. Values are members of the ContentAlignment enumeration, listed in Table 11-3. The default value is ContentAlignment.MiddleCenter.

Table 11-10. FlatStyle enumeration values

Value

Description

Flat

Control appears flat.

Popup

Control appears 3-D when the mouse cursor is over it, flat otherwise. The 3D appearance is the same as Standard.

Standard

Control appears 3-D.

System

Control appearance controlled by user's operating system. All image and alignment related properties of the control are ignored, as well as Button.BackColor. Use this value to force the control to conform to the system's theme.

A Button may be clicked with the mouse or an access key (discussed below). If a Button has focus, it may also be clicked by pressing Enter or the spacebar. When a Button is clicked, a Click event is raised. This event sends the event handler an argument of type EventArgs. The EventArgs event argument is essentially a placeholder, since it exposes no properties or information about the event.

In the programs listed in Example 11-5 (in C#) and Example 11-6 (in VB.NET), a form is created with a single button on it. The Text property of the button displays the value of the button's FlatStyle property. Each time the button is clicked, a new FlatStyle property is applied to the button, the Text property is changed to the current FlatStyle, and the size of the button is adjusted to the reflect the length of the displayed string. A happy face image is also displayed on the button for good measure. The resulting form looks like Figure 11-5.

Figure 11-5. ButtonFlatStyle program

figs/pnwa_1105.gif

This form would look much nicer if the button were centered. Several examples in Chapter 7 demonstrate how to do this. This example foregoes such niceties for the sake of concision.

 

Example 11-5. Button demonstration in C# (ButtonFlatStyle.cs)

figs/csharpicon.gif

using System;
using System.Drawing;
using System.Windows.Forms;
 
namespace ProgrammingWinApps
{
 public class ButtonFlatStyle : Form
 {
 Button btn;
 int i = 1;
 FlatStyle[ ] theStyles;
 Image img;
 
 public ButtonFlatStyle( )
 {
 Text = "Button Properties";
 Size = new Size(300,200);
 
 img = Image.FromFile(
 @"C:Program FilesMicrosoft Visual Studio .NET 2003" + 
 @"Common7Graphicsitmapsassortedhappy.bmp");
 
 btn = new Button( );
 btn.Parent = this;
 btn.Text = btn.FlatStyle.ToString( );
 btn.Location = new Point(10,10);
 btn.BackColor = Color.LightGreen;
 btn.Click += new System.EventHandler(btn_Click);
 btn.Image = img;
 btn.ImageAlign = ContentAlignment.MiddleRight;
 btn.TextAlign = ContentAlignment.MiddleLeft;
 
 ButtonSize(btn);
 
 // get the FlatStyle values into an array
 FlatStyle theEnum = new FlatStyle( );
 theStyles = (FlatStyle[ ])Enum.GetValues(theEnum.GetType( ));
 }
 
 static void Main( ) 
 {
 Application.Run(new ButtonFlatStyle( ));
 }
 
 private void btn_Click(object sender, EventArgs e)
 {
 Button btn = (Button)sender;
 btn.FlatStyle = theStyles[i];
 btn.Text = btn.FlatStyle.ToString( );
 ButtonSize(btn);
 
 if (i < theStyles.Length - 1)
 i++;
 else
 i = 0;
 }
 
 private void ButtonSize(Button btn)
 {
 int xSize = ((int)(Font.Height * .75) * btn.Text.Length) + 
 (img.Width * 2);
 int ySize = img.Height * 2;
 btn.Size = new Size(xSize, ySize);
 }
 }
}

Example 11-6. Button demonstration in VB.NET (ButtonFlatStyle.vb)

figs/vbicon.gif

Option Strict On
imports System
imports System.Drawing
imports System.Windows.Forms
 
namespace ProgrammingWinApps
 public class ButtonFlatStyle : inherits Form
 
 dim btn as Button
 dim i as integer
 dim theStyles as FlatStyle( )
 dim img as Image
 
 public sub New( )
 Text = "Button Properties"
 Size = new Size(300,200)
 
 img = Image.FromFile( _
 "C:\Program Files\Microsoft Visual Studio .NET 2003\" + _
 "Common7\Graphics\bitmaps\assorted\happy.bmp")
 btn = new Button( )
 btn.Parent = me
 btn.Text = btn.FlatStyle.ToString( )
 btn.Location = new Point(10,10)
 btn.BackColor = Color.LightGreen
 AddHandler btn.Click, AddressOf btn_Click
 btn.Image = img
 btn.ImageAlign = ContentAlignment.MiddleRight
 btn.TextAlign = ContentAlignment.MiddleLeft
 
 ButtonSize(btn)
 
 ' get the FlatStyle values into an array
 dim theEnum as new FlatStyle( )
 theStyles = CType([Enum].GetValues( _
 theEnum.GetType( )), FlatStyle( ))
 end sub
 
 public shared sub Main( ) 
 Application.Run(new ButtonFlatStyle( ))
 end sub
 
 private sub btn_Click(ByVal sender as object, _
 ByVal e as EventArgs)
 Dim btn as Button = CType(sender, Button)
 btn.FlatStyle = theStyles(i)
 btn.Text = btn.FlatStyle.ToString( )
 ButtonSize(btn)
 
 if (i < theStyles.Length - 1) then
 i = i + 1
 else
 i = 0
 end if
 end sub
 
 private sub ButtonSize(btn as Button)
 dim xSize as integer = (CType(Font.Height * .75, integer) * _
 btn.Text.Length) + (img.Width * 2)
 dim ySize as integer = img.Height * 2
 btn.Size = new Size(xSize, ySize)
 end sub
 end class
end namespace

The programs in Example 11-5 and Example 11-6 start off by declaring several class members, including a Button, an Image, an integer, and an array of FlatStyle objects. All of these members will be used throughout the class.

In the constructor, the image is instantiated to the bitmap contained in happy.bmp, a file included with the typical Visual Studio .NET installation. This is done by calling the static FromFile method of the Image class:

figs/csharpicon.gif

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

figs/vbicon.gif

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

The Button control was previously declared a member variable. Here it is instantiated, and its Parent property is set to the form:

figs/csharpicon.gif

btn = new Button( );
btn.Parent = this;

figs/vbicon.gif

btn = new Button( )
btn.Parent = me

The Text property of the button is set to a string representation of the current value of the button's FlatStyle property.

figs/csharpicon.gif

btn.Text = btn.FlatStyle.ToString( );

Since the FlatStyle property for this button has not yet been set, it will default to a value of Standard.

The Location of the button is set so the upper-left corner of the control will be 10 pixels in from the left edge of the form's client area and 10 pixels down from the top of the form's client area.

The background color of the button is set to LightGreen, which will not be obvious in this book, but will be visible on the screen.

The most commonly used event raised by the Button control is the Click event, although it supports all events common to the Control class other than DoubleClick. The Click event handler method is added to the event delegate with the appropriate following line of code:

figs/csharpicon.gif

btn.Click += new System.EventHandler(btn_Click);

figs/vbicon.gif

AddHandler btn.Click, AddressOf btn_Click

In either case, the name of the Click event handler method is btn_Click. It will be analyzed shortly.

.NET can suppress the DoubleClick event on Button controls by setting the StandardDoubleClick value of the ControlStyles enumeration.

The next three statements sets the Image property to the Image object previously instantiated with the happy face. The image is aligned to the middle of the right edge of the button, and the text is aligned to the middle of the button's left edge.

figs/csharpicon.gif

btn.Image = img;
btn.ImageAlign = ContentAlignment.MiddleRight;
btn.TextAlign = ContentAlignment.MiddleLeft;

Normally the button would be sized in the constructor. As you will soon see, though, you should also resize the button in its Click event handler. Therefore it makes sense to factor out the common code to a ButtonSize helper method, and call that method from both the constructor and the Click event handler.

The ButtonSize method takes an object of type Button as its argument. The passed-in Button object is the button that will be resized. The method is reproduced here:

figs/csharpicon.gif

private void ButtonSize(Button btn)
{
 int xSize = ((int)(Font.Height * .75) * btn.Text.Length) + 
 (img.Width * 2);
 int ySize = img.Height * 2;
 btn.Size = new Size(xSize, ySize);
}

figs/vbicon.gif

private sub ButtonSize(btn as Button)
 dim xSize as integer = (CType(Font.Height * .75, integer) * _
 btn.Text.Length) + (img.Width * 2)
 dim ySize as integer = img.Height * 2
 btn.Size = new Size(xSize, ySize)
end sub

The first statement in the method calculates the width of the button, based on multiplying the height of the form's current Font by a factor of 0.75 and adding twice the width of the Image object displayed on the button. The height of the button is calculated as twice the height of the Image object. (All of these factors were determined through trial and error to yield a desirable size.) Once the height and width of the button is calculated, the Size property of btn is set by declaring a new Size structure.

Several examples in Chapter 7 show different techniques of dynamically setting the size and location of controls.

The Click event handler accomplishes its task of cycling through the values of the FlatStyle enumeration by indexing into an array containing those enumeration values. It is accomplished with the following two statements:

figs/csharpicon.gif

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

figs/vbicon.gif

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

You have seen similar statements in other examples in this book, wherever it is necessary to iterate or otherwise treat an enumeration as an indexed collection.

Once the array is in hand, the btn_Click event handler method can use the integer counter i to index into the array, setting the style of the button to the desired value of FlatStyle. The event handler method is reproduced here:

figs/csharpicon.gif

private void btn_Click(object sender, EventArgs e)
{
 Button btn = (Button)sender;
 btn.FlatStyle = theStyles[i];
 btn.Text = btn.FlatStyle.ToString( );
 ButtonSize(btn);
 
 if (i < theStyles.Length - 1)
 i++;
 else
 i = 0;
}

figs/vbicon.gif

private sub btn_Click(ByVal sender as object, _
 ByVal e as EventArgs)
 Dim btn as Button = CType(sender, Button)
 btn.FlatStyle = theStyles(i)
 btn.Text = btn.FlatStyle.ToString( )
 ButtonSize(btn)
 
 if (i < theStyles.Length - 1) then
 i = i + 1
 else
 i = 0
 end if
 
end sub

The first statement in the method casts the object that raised the event as a Button and assigns it to a variable, btn, of type Button. Although a button raised the event that invoked the method, the compiler has no way of knowing this, so the explicit cast is necessary. The variable btn used in this method is not the same btn used in the constructor. Although they look the same, they are scoped independently. You could have called the Button variable in this method fred, and the method would still work exactly the same, although it would have been confusing.

The next two statements in the method assign the indexed value of the array of FlatStyles to the FlatStyle property of the button and assign the string representation of the FlatStyle property to the button's Text property. Then the ButtonSize method is called, as it was in the constructor, to resize the button.

Finally, the method checks the value of the counter and either increments it or resets it to zero.

When the FlatStyle is set to System, the Image and BackColor properties are ignored and the operating system controls the appearance of the button.

11.2.1 Button

The previous section covered features common to all the classes derived from the ButtonBase class, using a Button object as the test case. In this section, each of the derived classes, including Button, will be covered in detail.

11.2.1.1 DialogResult property

The Button control has one property, DialogResult, that is not derived from either ButtonBase or Control and not shared with CheckBox or RadioButton. The DialogResult property, which was covered in Chapter 6, is used with buttons on dialog boxes, such as a modal child form. The DialogResult property of a button returns a specific value from a dialog box. If a button on a dialog box has its DialogResult property set, the dialog box will be closed when the button is clicked. The value of the button's DialogResult property will be returned to the parent form as the dialog box's DialogResult property. This is all done without the programmer having to hook up events or write extra code.

The valid values of the DialogResult property, for either the button or the dialog box, must be members of the DialogResult enumeration, listed in Table 11-11. The default value is DialogResult.None.

Table 11-11. DialogResult enumeration

Value

Return value

Abort

Abort.

Cancel

Cancel.

Ignore

Ignore.

No

No.

None

Returns nothing. Modal dialog is not terminated.

OK

OK.

Retry

Retry.

Yes

Yes.

Refer to Chapter 6 for examples showing the usage of the DialogResult property.

11.2.1.2 PerformClick method

The PerformClick method generates a click event for the button. This method, which is not derived from Control but is shared with the RadioButton class, can be useful when you want the functionality contained in a button that will be invoked, without requiring the user to actually click the button.

Consider a form with two buttons, btn1 and btn2. Each has a Click event handler, shown here (the VB.NET versions are nearly identical):

figs/csharpicon.gif

private void btn1_Click(object sender, EventArgs e)
{
 MessageBox.Show("Button1 clicked.");
 btn2.PerformClick( );
}

private void btn2_Click(object sender, EventArgs e)
{
 MessageBox.Show("Button2 clicked.");
}

If the user clicks on btn2, a message box will display saying Button2 clicked. If the user clicks on btn1, the user will see two message boxes: Button1 clicked and Button2 clicked.

11.2.1.3 Access keys

In addition to clicking with the mouse, a button can be clicked by an access key. An access key is specified by inserting an ampersand in front of the desired character in the button's Text property. That character will be underlined on the button's face. The button can be clicked, even if it does not have focus, by pressing the access key simultaneously with the Alt key.

If the Text property needs to show an ampersand character, escape it by doubling the ampersand.

The following code snippet specifies a button:

figs/csharpicon.gif

btn1 = new Button( );
btn1.Parent = this;
btn1.Text = "&Cut && Paste";
btn1.Location = new Point(10,10);
btn1.Click += new System.EventHandler(btn1_Click);

This would create a button displaying the legend Cut & Paste. Pressing Alt-C would click the button, regardless of which control on the form had focus.

11.2.1.4 Form Button properties

The Form class provides two properties that allow specified buttons to be clicked using specific keys on the keyboard, even if those buttons do not have focus.

The form AcceptButton property lets you get or set a button that will be clicked if the user presses Enter, even if that button does not have focus. The only time Enter will not click the designated button would be if the currently selected control intercepts the Enter key. For example, a multiline text box will process the Enter key as part of its text, preventing it from triggering AcceptButton.

The form CancelButton property lets you get or set a button that will be clicked if the user presses Escape, even if that button does not have focus.

Consider a form called frmMain with two buttons, btnOK and btnCancel. The following code snippet (in C#) from the constructor of the form sets the AcceptButton and CancelButton properties of the form:

figs/csharpicon.gif

frmMain.AcceptButton = btnOK;
frmMain.CancelButton = btnCancel;

If the user presses Enter, btnOK will be clicked, and if she presses Escape, btnCancel will be clicked.

11.2.2 CheckBox

The CheckBox control is derived from the ButtonBase class, as are the Button and RadioButton controls. It is typically used to indicate a Boolean such as Yes/No or True/False.

A CheckBox normally consists of a small square with a text string next to it. Clicking on either the square or the associated text string toggles the state of the control. If the square is checked, it becomes unchecked, and vice versa. If the control has focus, the state can also be toggled by pressing the spacebar.

The normal appearance of the CheckBox can be changed to resemble a button by setting the Appearance property. The button appears depressed when checked and raised when unchecked. Unlike a true button control, it retains the depressed appearance until it is clicked again, which causes it to toggle to the raised position.

The most important property of the Checkbox control is the Checked property. It either sets the state of the control or determines whether the control is checked or unchecked. If the AutoCheck property is true (the default value), then the Checked property will be changed automatically when the CheckBox is clicked. If you set the AutoCheck property to false, then you must explicitly set the Checked property in a Click event handler.

The commonly used properties of the CheckBox control are listed in Table 11-12.

Table 11-12. CheckBox properties

Property

Value type

Description

Appearance

Appearance

Read/write. If the value is Appearance.Normal (the default), then the checkbox will have a normal appearance. If the value is Appearance.Button, the checkbox will look like a button that toggles, (either in an up or down state).

AutoCheck

Boolean

Read/write. Value indicating if the Checked or CheckState properties are automatically changed when the Click event is raised. If true (the default), those properties will be automatically changed when the control is clicked.

CheckAlign

ContentAlignment

Read/write. Controls both the horizontal and vertical alignment of the checkbox in a CheckBox control. Valid values must come from the ContentAlignment enumeration, listed in Table 11-3. The default is ContentAlignment.MiddleLeft.

Checked

Boolean

Read/write. Value indicating the state of the checkbox. If true, the checkbox is checked, otherwise false (the default).

CheckState

CheckState

Read/write. The state of the checkbox. The valid values must be members of the CheckState enumeration, listed in Table 11-13. The default value is CheckState.Unchecked.

TextAlign

ContentAlignment

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

ThreeState

Boolean

Read/write. Value indicating if the control can display three states or two. If true, the checkbox can display three states, otherwise false (the default).

The CheckBox control has a ThreeState property that, if true, allows it to indicate an indeterminate state in addition to the Boolean values. If the ThreeState property of the control is true, then each time it is clicked, its state cycles through the three values of the CheckState enumeration: Checked, Unchecked, and Indeterminate.

A good example of a CheckBox making use of the ThreeState property can be found in the Font dialog box used in Microsoft Word. This dialog box has several checkboxes, one each for effects such as Strikethrough, Superscript, or Subscript. If you highlight a word with no effects applied to and then open the Font dialog box, none of the checkboxes will be checked. Check the Strikethrough checkbox, and then close the dialog box, and the word will have a line through it. Leaving the word highlighted, open the dialog box again and now the Strikethrough checkbox will be checked. This is typical two-state behaviorthe text selection is unambiguously struck through. However, if you highlight the entire line of text with both normal words and struck-through words and then open the Font dialog box, the Strikethrough checkbox will have a checkmark, but the square and the checkmark will be gray. This is the indeterminate state, since the selection has both struck-through and non-struck-through characters.

If the ThreeState property is true, then use the CheckState property rather than the Checked property to get or set the state of the checkbox. The valid values of the CheckState property are members of the CheckState enumeration, listed in Table 11-13.

Table 11-13. CheckState enumeration

Value

Appearance.Normal

Appearance.Button

Checked

Displays checkmark

Button looks depressed

Unchecked

No checkmark

Button looks raised

Indeterminate

Displays checkmark in shaded checkbox

Button looks flat

The CheckBox control has many events, most of which are inherited from the Control class. Table 11-14 lists the most commonly used events. Of those, only the Click event is inherited from Control. If the AutoCheck property is set to its default value of true, then there is rarely any need to handle the Click event.

Table 11-14. CheckBox events

Property

Event argument

Description

AppearanceChanged

EventArgs

Raised when the Appearance property of the control changes

CheckedChanged

EventArgs

Raised when the Checked property of the control changes

CheckStateChanged

EventArgs

Raised when the CheckState property of the control changes

Click

EventArgs

Raised when the control is clicked.

The programs listed in Example 11-7 and Example 11-8 demonstrate the basic features of using CheckBox controls. The Appearance, CheckAlign, and TextAlign properties will be demonstrated in Example 11-9 and Example 11-10 in the next section, where RadioButton controls will be used to change these CheckBox properties. In the next example, a checkbox is created for each member of the FontStyle enumeration. Clicking on one or more of the checkboxes applies that font style to the text contained in a label control. The checkboxes are contained in a Panel control to allow easy iteration through the checkboxes in the CheckedChanged event handler. When the examples are compiled and run, the program will look like the screenshot shown in Figure 11-6.

Figure 11-6. CheckBoxes

figs/pnwa_1106.gif

Example 11-7. CheckBoxes using C# (CheckBoxes.cs)

figs/csharpicon.gif

using System;
using System.Drawing;
using System.Windows.Forms;
 
namespace ProgrammingWinApps
{
 public class CheckBoxes : Form
 {
 Label lbl;
 Panel pnl;
 FontStyle[ ] theStyles;
 
 public CheckBoxes( )
 {
 Text = "CheckBoxes";
 Size = new Size(300,250);
 
 lbl = new Label( );
 lbl.Parent = this;
 lbl.Text = "The quick brown fox...";
 lbl.Location = new Point(0,0);
 lbl.AutoSize = true;
 lbl.BorderStyle = BorderStyle.Fixed3D;
 int yDelta = lbl.Height + 10;
 
 FontStyle theEnum = new FontStyle( );
 theStyles = (FontStyle[ ])Enum.GetValues(theEnum.GetType( ));
 
 pnl = new Panel( );
 pnl.Parent = this;
 pnl.Location = new Point(0, yDelta );
 pnl.Size = new Size(150, (theStyles.Length + 1) * yDelta);
 pnl.BorderStyle = BorderStyle.FixedSingle;
 
 int i = 1;
 CheckBox cb;
 foreach (FontStyle style in theStyles)
 {
 cb = new CheckBox( );
 cb.Parent = pnl;
 cb.Location = new Point(25, (yDelta * (i - 1)) + 10);
 cb.Size = new Size(75,20);
 cb.Text = style.ToString( );
 cb.Tag = style;
 cb.CheckedChanged += 
 new System.EventHandler(cb_CheckedChanged);
 if (cb.Text = = "Regular")
 cb.Checked = true;
 i++;
 }
 }
 
 static void Main( ) 
 {
 Application.Run(new CheckBoxes( ));
 }
 
 private void cb_CheckedChanged(object sender, EventArgs e)
 {
 FontStyle fs = 0;
 for (int i = 0; i < pnl.Controls.Count; i++)
 {
 CheckBox cb = (CheckBox)pnl.Controls[i];
 if (cb.Checked)
 fs |= (FontStyle)cb.Tag;
 
// The following lines accomplish the same task in a more condensed way.
// if (((CheckBox)pnl.Controls[i]).Checked)
// fs |= (FontStyle)((CheckBox)pnl.Controls[i]).Tag;
 }
 lbl.Font = new Font(lbl.Font, fs);
 }
 }
}

Example 11-8. CheckBoxes using VB.NET (CheckBoxes.vb)

figs/vbicon.gif

Option Strict On
imports System
imports System.Drawing
imports System.Windows.Forms
 
namespace ProgrammingWinApps
 public class CheckBoxes : inherits Form
 
 dim lbl as Label
 dim pnl as Panel
 dim theStyles as FontStyle( )
 
 public sub New( )
 Text = "Button Properties"
 Size = new Size(300,250)
 
 lbl = new Label( )
 lbl.Parent = me
 lbl.Text = "The quick brown fox..."
 lbl.Location = new Point(0,0)
 lbl.AutoSize = true
 lbl.BorderStyle = BorderStyle.Fixed3D
 
 dim yDelta as integer = lbl.Height + 10
 
 ' get the FontStyle values into an array
 dim theEnum as new FontStyle( )
 theStyles = CType([Enum].GetValues( _
 theEnum.GetType( )), FontStyle( ))
 
 pnl = new Panel( )
 pnl.Parent = me
 pnl.Location = new Point(0, yDelta )
 pnl.Size = new Size(150, (theStyles.Length + 1) * yDelta)
 pnl.BorderStyle = BorderStyle.FixedSingle
 
 dim i as integer = 1
 dim style as FontStyle
 dim cb as CheckBox
 for each style in theStyles
 cb = new CheckBox( )
 cb.Parent = pnl
 cb.Location = new Point(25, (yDelta * (i - 1)) + 10)
 cb.Size = new Size(75,20)
 cb.Text = style.ToString( )
 cb.Tag = style
 AddHandler cb.CheckedChanged, AddressOf cb_CheckedChanged
 
 if cb.Text = "Regular" then
 cb.Checked = true
 end if
 i = i + 1
 next
 end sub
 
 public shared sub Main( ) 
 Application.Run(new CheckBoxes( ))
 end sub
 
 private sub cb_CheckedChanged(ByVal sender as object, _
 ByVal e as EventArgs)
 dim fs as FontStyle = 0
 dim i as integer
 for i = 0 to pnl.Controls.Count - 1
 dim cb as CheckBox = CType(pnl.Controls(i), CheckBox)
 if cb.Checked then
 fs = fs or CType(cb.Tag, FontStyle)
 end if
 
' The following lines accomplish the same task in a more condensed way.
' if (CType(pnl.Controls(i), CheckBox)).Checked then
' fs = fs or CType(CType(pnl.Controls(i), _
' CheckBox).Tag, FontStyle)
' end if
 next
 
 lbl.Font = new Font(lbl.Font, fs)
 end sub
 end class
end namespace

Three member variables are declared, so they will be available to all methodstwo controls and an array of FontStyle objects:

figs/csharpicon.gif

Label lbl;
Panel pnl;
FontStyle[ ] theStyles;

figs/vbicon.gif

dim lbl as Label
dim pnl as Panel
dim theStyles as FontStyle( )

In the constructor, the Label control is instantiated and specified with several properties, including a Text property that will be displayed on the form. An integer yDelta is calculated, and will be used soon for positioning other controls.

The next two statements put the contents of the FontStyle enumeration into an array. This is necessary because you cannot iterate through an enumeration directly, and you will need to iterate before creating one checkbox for each member of the enumeration. You have seen similar code in previous examples.

figs/csharpicon.gif

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

figs/vbicon.gif

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

This array is then looped through using a foreach loop, creating a CheckBox for each member of the enumeration. The Parent property of each CheckBox is set as the Panel control. This setting facilitates iterating through all the checkbox controls in the event handler, since it cleanly encapsulates the collection of checkbox controls within a container control. (The Panel control will be covered in detail in Chapter 13.)

The Tag property of each checkbox control is set to its associated FontStyle. This allows the Tag property to be used in the event handler to set the FontStyle directly without having to cast a text string to a FontStyle.

An event handler method, cb_CheckedChanged, is added to the delegate for the CheckedChanged event. When the CheckBox is changed, the CheckedChanged event is fired, which is then handled by that method:

figs/csharpicon.gif

cb.CheckedChanged += new System.EventHandler(cb_CheckedChanged);
AddHandler cb.CheckedChanged, AddressOf cb_CheckedChanged

Finally, the Text property of the checkbox is tested. If it is Regular, then the Checked property of that checkbox is set to true so the checkbox will appear checked. Regular is the default value at program initialization.

The cb_CheckedChanged event handler is called every time one of the checkboxes has a changed value. It is not necessary for all checkbox controls in a group to use the same event handler, but in this case it serves the goal of the program, which is to apply one or more FontStyles to the Label control's Text property.

FontStyles can be added together bitwise using the logical OR operator. This is done by iterating through each of the checkbox controls, testing to see if the checkbox is checked, and if it is checked, OR'ing its Tag property to the built-up FontStyle variable.

The method starts by declaring, instantiating, and initializing the FontStyle variable to 0:

figs/csharpicon.gif

FontStyle fs = 0;

figs/vbicon.gif

dim fs as FontStyle = 0

Then the Controls collection of the Panel control is iterated. Within the for loop, each member of the Panel's Controls collection is cast to a CheckBox:

figs/csharpicon.gif

CheckBox cb = (CheckBox)pnl.Controls[i];

figs/vbicon.gif

dim cb as CheckBox = CType(pnl.Controls(i), CheckBox)

Then the Checked property of that checkbox is tested. If it is checked, the value of its Tag property is OR'ed to the pre-existing FontStyle variable:

figs/csharpicon.gif

if (cb.Checked)
 fs |= (FontStyle)cb.Tag;

figs/vbicon.gif

if cb.Checked then
 fs = fs or CType(cb.Tag, FontStyle)
end if

You can condense the casting of the control into the testing for a gain in code density but a loss of readability. The necessary lines are commented out in the example. It would be:

figs/csharpicon.gif

if (((CheckBox)pnl.Controls[i]).Checked)
 fs |= (FontStyle)((CheckBox)pnl.Controls[i]).Tag;

figs/vbicon.gif

if (CType(pnl.Controls(i), CheckBox)).Checked then
 fs = fs or CType(CType(pnl.Controls(i), _
 CheckBox).Tag, FontStyle)
end if

Finally, the FontStyle is applied to the Label control by creating a new Font object that uses the current Font property as a template.

figs/csharpicon.gif

lbl.Font = new Font(lbl.Font, fs);

11.2.3 RadioButton

The RadioButton control, the last of the ButtonBase derived controls, is similar to the CheckBox. The main difference between the RadioButton and the CheckBox is that RadioButton controls are typically grouped with other RadioButtons and only one of the controls in the group can be checked at one time. In other words, if an unchecked radio button in a group is clicked by the user, the currently checked radio button will become unchecked automatically (assuming that the AutoClick property is set to the default value of true).

RadioButtons are typically grouped by a container control. These controls include Panels and GroupBoxes, both of which are described in Chapter 13. If one or more RadioButtons are on the form but not in a container control, then those "freestanding" radio buttons are grouped together.

The essential difference between a Panel control and a GroupBox control is that a Panel control can have scrollbars but no caption, while a GroupBox control can have a Text property that will appear as a caption, but no scrollbars.

If two or more groups of radio buttons are on a form, they will be totally independent of each other. There can be at most one checked radio button in each group, but changing the Checked state of the radio buttons in one group will have no effect on the other group.

The RadioButton control has the same common properties as the CheckBox control, listed in Table 11-12, with the omission of the ThreeState related properties: CheckState and ThreeState. Likewise, it has the same events as the CheckBox events listed in Table 11-14, with the omission of CheckStateChanged.

The RadioButton control has one method not derived from Control (or some other base class), but shared with the Button control: the PerformClick method. It behaves the same as it does with the Button control, described previously in this chapter.

Example 11-9 and Example 11-10 build on the examples used to demonstrate CheckBoxes and showing how to use radio buttons to change properties of a CheckBox control. The finished program is shown in Figure 11-7.

Figure 11-7. RadioButtons

figs/pnwa_1107.gif

The example programs add three GroupBox controls, each of which contains a group of RadioButton controls. Clicking on any of the radio buttons changes the appearance of the checkboxes. The Appearance group lets you toggle between Normal and Button values for the Appearance property. The CheckAlign group changes the values of the CheckAlign property of the CheckBox control, and the TextAlign group changes the TextAlign property.

Although this program changes the appearance of the CheckBox control, RadioButton controls behave and appear much like the CheckBox control.

When there are only two choices in a radio button group, you can use a single CheckBox instead. For example, you could replace the Appearance radio buttons with a single CheckBox labeled Button. When checked, it would set the Appearance property to Appearance.Button, and when unchecked it would set the value to Appearance.Normal. The main advantage of using a radio button in this case is that both available options are explicitly displayed to the user.

The changes in Example 11-9 and Example 11-10 from Example 11-7 and Example 11-8 are highlighted. These code listings are long, but there is a fair amount of repetitious code that you can cut and paste with minor changes. If you are developing with Visual Studio .NET, much of this code will be generated for you automatically.

If you are developing with Visual Studio .NET, dragging and dropping radio buttons into different groups, you must take care to first create the container control for the radio buttons and then drag-and-drop the RadioButton controls onto the container control. This will ensure that the correct parent/child relationships are formed.

 

Example 11-9. RadioButton controls using C# (RadioButtons.cs)

figs/csharpicon.gif

using System;
using System.Drawing;
using System.Windows.Forms;
 
namespace ProgrammingWinApps
{
 public class RadioButtons : Form
 {
 Label lbl;
 Panel pnl;
 int yDelta;
 RadioButton rdoAppearanceNormal;
 RadioButton rdoAppearanceButton;
 RadioButton rdoCheckAlignMiddleLeft;
 RadioButton rdoCheckAlignMiddleRight;
 RadioButton rdoTextAlignMiddleLeft;
 RadioButton rdoTextAlignMiddleRight;
 RadioButton rdoTextAlignMiddleCenter;
 FontStyle[ ] theStyles;
 
 public RadioButtons( )
 {
 Text = "RadioButtons";
 Size = new Size(350,375);
 
 lbl = new Label( );
 lbl.Parent = this;
 lbl.Text = "The quick brown fox...";
 lbl.Location = new Point(0,0);
 lbl.AutoSize = true;
 lbl.BorderStyle = BorderStyle.Fixed3D;
 yDelta = lbl.Height + 10;
 
 // Get the FontStyles into an array
 FontStyle theEnum = new FontStyle( );
 theStyles = (FontStyle[ ])Enum.GetValues(theEnum.GetType( ));
 
 pnl = new Panel( );
 pnl.Parent = this;
 pnl.Location = new Point(0, yDelta );
 pnl.Size = new Size(150, (theStyles.Length + 1) * yDelta);
 pnl.BorderStyle = BorderStyle.None;
 
 int i = 1;
 CheckBox cb;
 foreach (FontStyle style in theStyles)
 {
 cb = new CheckBox( );
 cb.Parent = pnl;
 cb.Location = new Point(25, (yDelta * (i - 1)) + 10);
 cb.Size = new Size(75,20);
 cb.Text = style.ToString( );
 cb.Tag = style;
 cb.CheckedChanged += 
 new System.EventHandler(cb_CheckedChanged);
 if (cb.Text = = "Regular")
 cb.Checked = true;
 i++;
 }
 
 GroupBox grpAppearance = new GroupBox( );
 grpAppearance.Parent = this;
 grpAppearance.Text = "Appearance";
 grpAppearance.Location = new Point(175,yDelta);
 grpAppearance.Size = new Size(150, yDelta * 3);
 
 rdoAppearanceNormal = new RadioButton( );
 rdoAppearanceNormal.Parent = grpAppearance;
 rdoAppearanceNormal.Text = "Normal"; 
 rdoAppearanceNormal.Location = new Point(10, 15);
 rdoAppearanceNormal.Checked = true;
 rdoAppearanceNormal.CheckedChanged += 
 new System.EventHandler(rdoAppearance_CheckedChanged);
 
 rdoAppearanceButton = new RadioButton( );
 rdoAppearanceButton.Parent = grpAppearance;
 rdoAppearanceButton.Text = "Button"; 
 rdoAppearanceButton.Location = new Point(10, 15 + yDelta);
 rdoAppearanceButton.CheckedChanged += 
 new System.EventHandler(rdoAppearance_CheckedChanged);
 
 GroupBox grpCheckAlign = new GroupBox( );
 grpCheckAlign.Parent = this;
 grpCheckAlign.Text = "CheckAlign";
 grpCheckAlign.Location = new Point(175, 
 grpAppearance.Bottom + 25);
 grpCheckAlign.Size = new Size(150, yDelta * 3);
 
 rdoCheckAlignMiddleLeft = new RadioButton( );
 rdoCheckAlignMiddleLeft.Parent = grpCheckAlign;
 rdoCheckAlignMiddleLeft.Text = "Middle Left"; 
 rdoCheckAlignMiddleLeft.Tag = ContentAlignment.MiddleLeft;
 rdoCheckAlignMiddleLeft.Location = new Point(10, 15);
 rdoCheckAlignMiddleLeft.Checked = true;
 rdoCheckAlignMiddleLeft.CheckedChanged += 
 new System.EventHandler(rdoCheckAlign_CheckedChanged);
 
 rdoCheckAlignMiddleRight = new RadioButton( );
 rdoCheckAlignMiddleRight.Parent = grpCheckAlign;
 rdoCheckAlignMiddleRight.Text = "Middle Right"; 
 rdoCheckAlignMiddleRight.Tag = ContentAlignment.MiddleRight;
 rdoCheckAlignMiddleRight.Location = new Point(10, 15 + yDelta);
 rdoCheckAlignMiddleRight.CheckedChanged += 
 new System.EventHandler(rdoCheckAlign_CheckedChanged);
 
 GroupBox grpTextAlign = new GroupBox( );
 grpTextAlign.Parent = this;
 grpTextAlign.Text = "TextAlign";
 grpTextAlign.Location = new Point(175, 
 grpCheckAlign.Bottom + 25);
 grpTextAlign.Size = new Size(150, yDelta * 4);
 
 rdoTextAlignMiddleLeft = new RadioButton( );
 rdoTextAlignMiddleLeft.Parent = grpTextAlign;
 rdoTextAlignMiddleLeft.Text = "Middle Left"; 
 rdoTextAlignMiddleLeft.Tag = ContentAlignment.MiddleLeft;
 rdoTextAlignMiddleLeft.Location = new Point(10, 15);
 rdoTextAlignMiddleLeft.Checked = true;
 rdoTextAlignMiddleLeft.CheckedChanged += 
 new System.EventHandler(rdoTextAlign_CheckedChanged);
 
 rdoTextAlignMiddleRight = new RadioButton( );
 rdoTextAlignMiddleRight.Parent = grpTextAlign;
 rdoTextAlignMiddleRight.Text = "Middle Right"; 
 rdoTextAlignMiddleRight.Tag = ContentAlignment.MiddleRight;
 rdoTextAlignMiddleRight.Location = new Point(10, 15 + yDelta);
 rdoTextAlignMiddleRight.CheckedChanged += 
 new System.EventHandler(rdoTextAlign_CheckedChanged);
 
 rdoTextAlignMiddleCenter = new RadioButton( );
 rdoTextAlignMiddleCenter.Parent = grpTextAlign;
 rdoTextAlignMiddleCenter.Text = "Middle Center"; 
 rdoTextAlignMiddleCenter.Tag = ContentAlignment.MiddleCenter;
 rdoTextAlignMiddleCenter.Location = new Point(10, 
 15 + (2 * yDelta));
 rdoTextAlignMiddleCenter.CheckedChanged += 
 new System.EventHandler(rdoTextAlign_CheckedChanged);
 } // close for constructor
 
 static void Main( ) 
 {
 Application.Run(new RadioButtons( ));
 }
 
 private void cb_CheckedChanged(object sender, EventArgs e)
 {
 FontStyle fs = 0;
 for (int i = 0; i < pnl.Controls.Count; i++)
 {
 CheckBox cb = (CheckBox)pnl.Controls[i];
 if (cb.Checked)
 fs |= (FontStyle)cb.Tag;
 }
 lbl.Font = new Font(lbl.Font, fs);
 }
 
 private void rdoAppearance_CheckedChanged(object sender, 
 EventArgs e)
 {
 if (rdoAppearanceNormal.Checked)
 {
 for (int i = 0; i < pnl.Controls.Count; i++)
 {
 CheckBox cb = (CheckBox)pnl.Controls[i];
 cb.Appearance = Appearance.Normal;
 }
 }
 else
 {
 for (int i = 0; i < pnl.Controls.Count; i++)
 {
 CheckBox cb = (CheckBox)pnl.Controls[i];
 cb.Appearance = Appearance.Button;
 }
 }
 }
 
 private void rdoCheckAlign_CheckedChanged(object sender, 
 EventArgs e)
 {
 RadioButton rdo = (RadioButton)sender;
 for (int i = 0; i < pnl.Controls.Count; i++)
 {
 CheckBox cb = (CheckBox)pnl.Controls[i];
 cb.CheckAlign = (ContentAlignment)rdo.Tag;
 }
 }
 
 private void rdoTextAlign_CheckedChanged(object sender, EventArgs e)
 {
 RadioButton rdo = (RadioButton)sender;
 for (int i = 0; i < pnl.Controls.Count; i++)
 {
 CheckBox cb = (CheckBox)pnl.Controls[i];
 switch ((int)rdo.Tag)
 {
 case (int)ContentAlignment.MiddleLeft : 
 cb.TextAlign = ContentAlignment.MiddleLeft;
 break;
 case (int)ContentAlignment.MiddleRight : 
 cb.TextAlign = ContentAlignment.MiddleRight;
 break;
 case (int)ContentAlignment.MiddleCenter : 
 cb.TextAlign = ContentAlignment.MiddleCenter;
 break;
 }
 }
 } // close for rdoTextAlign_CheckedChanged 
 } // close for form class
} // close form namespace

Example 11-10. RadioButton controls using VB.NET (RadioButtons.vb)

figs/vbicon.gif

Option Strict On
imports System
imports System.Drawing
imports System.Windows.Forms
 
namespace ProgrammingWinApps
 public class RadioButtons : inherits Form
 
 dim lbl as Label
 dim pnl as Panel
 dim yDelta as integer
 dim rdoAppearanceNormal as RadioButton
 dim rdoAppearanceButton as RadioButton
 dim rdoCheckAlignMiddleLeft as RadioButton
 dim rdoCheckAlignMiddleRight as RadioButton
 dim rdoTextAlignMiddleLeft as RadioButton
 dim rdoTextAlignMiddleRight as RadioButton
 dim rdoTextAlignMiddleCenter as RadioButton
 dim theStyles as FontStyle( )
 
 public sub New( )
 Text = "RadioButtons"
 Size = new Size(350,375)
 
 lbl = new Label( )
 lbl.Parent = me
 lbl.Text = "The quick brown fox..."
 lbl.Location = new Point(0,0)
 lbl.AutoSize = true
 lbl.BorderStyle = BorderStyle.Fixed3D
 yDelta = lbl.Height + 10
 
 ' get the FontStyle values into an array
 dim theEnum as new FontStyle( )
 theStyles = CType([Enum].GetValues( _
 theEnum.GetType( )), FontStyle( ))
 
 pnl = new Panel( )
 pnl.Parent = me
 pnl.Location = new Point(0, yDelta )
 pnl.Size = new Size(150, (theStyles.Length + 1) * yDelta)
 pnl.BorderStyle = BorderStyle.None
 
 dim i as integer = 1
 dim style as FontStyle
 dim cb as CheckBox
 for each style in theStyles
 cb = new CheckBox( )
 cb.Parent = pnl
 cb.Location = new Point(25, (yDelta * (i - 1)) + 10)
 cb.Size = new Size(75,20)
 cb.Text = style.ToString( )
 cb.Tag = style
 AddHandler cb.CheckedChanged, AddressOf cb_CheckedChanged
 
 if cb.Text = "Regular" then
 cb.Checked = true
 end if
 i = i + 1
 next
 
 dim grpAppearance as GroupBox = new GroupBox( )
 grpAppearance.Parent = me
 grpAppearance.Text = "Appearance"
 grpAppearance.Location = new Point(175,yDelta)
 grpAppearance.Size = new Size(150, yDelta * 3)
 
 rdoAppearanceNormal = new RadioButton( )
 rdoAppearanceNormal.Parent = grpAppearance
 rdoAppearanceNormal.Text = "Normal"
 rdoAppearanceNormal.Location = new Point(10, 15)
 rdoAppearanceNormal.Checked = true
 AddHandler rdoAppearanceNormal.CheckedChanged, _
 AddressOf rdoAppearance_CheckedChanged
 
 rdoAppearanceButton = new RadioButton( )
 rdoAppearanceButton.Parent = grpAppearance
 rdoAppearanceButton.Text = "Button"
 rdoAppearanceButton.Location = new Point(10, 15 + yDelta)
 AddHandler rdoAppearanceButton.CheckedChanged, _
 AddressOf rdoAppearance_CheckedChanged
 
 dim grpCheckAlign as GroupBox = new GroupBox( )
 grpCheckAlign.Parent = me
 grpCheckAlign.Text = "CheckAlign"
 grpCheckAlign.Location = new Point(175, _
 grpAppearance.Bottom + 25)
 grpCheckAlign.Size = new Size(150, yDelta * 3)
 
 rdoCheckAlignMiddleLeft = new RadioButton( )
 rdoCheckAlignMiddleLeft.Parent = grpCheckAlign
 rdoCheckAlignMiddleLeft.Text = "Middle Left"
 rdoCheckAlignMiddleLeft.Tag = ContentAlignment.MiddleLeft
 rdoCheckAlignMiddleLeft.Location = new Point(10, 15)
 rdoCheckAlignMiddleLeft.Checked = true
 AddHandler rdoCheckAlignMiddleLeft.CheckedChanged, _
 AddressOf rdoCheckAlign_CheckedChanged
 
 rdoCheckAlignMiddleRight = new RadioButton( )
 rdoCheckAlignMiddleRight.Parent = grpCheckAlign
 rdoCheckAlignMiddleRight.Text = "Middle Right"
 rdoCheckAlignMiddleRight.Tag = ContentAlignment.MiddleRight
 rdoCheckAlignMiddleRight.Location = new Point(10, 15 + yDelta)
 AddHandler rdoCheckAlignMiddleRight.CheckedChanged, _
 AddressOf rdoCheckAlign_CheckedChanged
 
 dim grpTextAlign as GroupBox = new GroupBox( )
 grpTextAlign.Parent = me
 grpTextAlign.Text = "TextAlign"
 grpTextAlign.Location = new Point(175, grpCheckAlign.Bottom + 25)
 grpTextAlign.Size = new Size(150, yDelta * 4)
 
 rdoTextAlignMiddleLeft = new RadioButton( )
 rdoTextAlignMiddleLeft.Parent = grpTextAlign
 rdoTextAlignMiddleLeft.Text = "Middle Left"
 rdoTextAlignMiddleLeft.Tag = ContentAlignment.MiddleLeft
 rdoTextAlignMiddleLeft.Location = new Point(10, 15)
 rdoTextAlignMiddleLeft.Checked = true
 AddHandler rdoTextAlignMiddleLeft.CheckedChanged, _
 AddressOf rdoTextAlign_CheckedChanged
 
 rdoTextAlignMiddleRight = new RadioButton( )
 rdoTextAlignMiddleRight.Parent = grpTextAlign
 rdoTextAlignMiddleRight.Text = "Middle Right"
 rdoTextAlignMiddleRight.Tag = ContentAlignment.MiddleRight
 rdoTextAlignMiddleRight.Location = new Point(10, 15 + yDelta)
 AddHandler rdoTextAlignMiddleRight.CheckedChanged, _
 AddressOf rdoTextAlign_CheckedChanged
 
 rdoTextAlignMiddleCenter = new RadioButton( )
 rdoTextAlignMiddleCenter.Parent = grpTextAlign
 rdoTextAlignMiddleCenter.Text = "Middle Center"
 rdoTextAlignMiddleCenter.Tag = ContentAlignment.MiddleCenter
 rdoTextAlignMiddleCenter.Location = new Point(10, _
 15 + (2 * yDelta))
 AddHandler rdoTextAlignMiddleCenter.CheckedChanged, _
 AddressOf rdoTextAlign_CheckedChanged
 end sub ' close for constructor
 
 public shared sub Main( ) 
 Application.Run(new RadioButtons( ))
 end sub
 
 private sub cb_CheckedChanged(ByVal sender as object, _
 ByVal e as EventArgs)
 dim fs as FontStyle = 0
 dim i as integer
 for i = 0 to pnl.Controls.Count - 1
 dim cb as CheckBox = CType(pnl.Controls(i), CheckBox)
 if cb.Checked then
 fs = fs or CType(cb.Tag, FontStyle)
 end if
 next
 lbl.Font = new Font(lbl.Font, fs)
 end sub
 
 private sub rdoAppearance_CheckedChanged(ByVal sender as object, _
 ByVal e as EventArgs)
 dim i as integer
 if rdoAppearanceNormal.Checked then
 for i = 0 to pnl.Controls.Count - 1
 dim cb as CheckBox = CType(pnl.Controls(i), CheckBox)
 cb.Appearance = Appearance.Normal
 next
 else
 for i = 0 to pnl.Controls.Count - 1
 dim cb as CheckBox = CType(pnl.Controls(i), CheckBox)
 cb.Appearance = Appearance.Button
 next
 end if
 end sub
 
 private sub rdoCheckAlign_CheckedChanged(ByVal sender as object, _
 ByVal e as EventArgs)
 dim rdo as RadioButton = CType(sender, RadioButton)
 dim i as integer
 for i = 0 to pnl.Controls.Count - 1
 dim cb as CheckBox = CType(pnl.Controls(i), CheckBox)
 cb.CheckAlign = CType(rdo.Tag, ContentAlignment)
 next
 end sub
 
 private sub rdoTextAlign_CheckedChanged(ByVal sender as object, _
 ByVal e as EventArgs)
 dim rdo as RadioButton = CType(sender, RadioButton)
 dim i as integer
 for i = 0 to pnl.Controls.Count - 1
 dim cb as CheckBox = CType(pnl.Controls(i), CheckBox)
 select case rdo.Tag 
 case ContentAlignment.MiddleLeft 
 cb.TextAlign = ContentAlignment.MiddleLeft
 case ContentAlignment.MiddleRight 
 cb.TextAlign = ContentAlignment.MiddleRight
 case ContentAlignment.MiddleCenter 
 cb.TextAlign = ContentAlignment.MiddleCenter
 end select
 next
 end sub 
 end class
end namespace

The first significant difference in these examples is that the yDelta variable is now a member of the class (and thus available to all the methods of the class).

There are a number of relatively minor changes in the constructor. The Text property and Size of the form has been modified and the instantiation of yDelta now reflects the fact that it is a member variable rather than a local variable. The BorderStyle of the Panel control has been set to BorderStyle.None so that it will not be visible on the form, but will still function as a container of the CheckBoxes.

Now comes the meat of the differences in the constructor. There are three new GroupBox controls, each containing several RadioButton controls. Each set of radio buttons within a group box are mutually exclusive: only one radio button in each group can be checked at the same time.

Within each group, the radio button corresponding to the default value has its Checked property set to true so that the form will initialize with the correctly checked radio button. yDelta is used for calculating the Location and Size properties of many of the controls. The Location property of the second and third group boxes are calculated based on the Bottom property of the previous group box. Here are the lines of code that set the Location property for each group box (the same in both languages except for the trailing semicolon):

figs/csharpicon.gif

grpAppearance.Location = new Point(175,yDelta);
grpCheckAlign.Location = new Point(175, grpAppearance.Bottom + 25);
grpTextAlign.Location = new Point(175, grpCheckAlign.Bottom + 25);

An event handler is added to the CheckedChanged delegate for each RadioButton control, as was done in the CheckBox control. One event handler is used for all the radio buttons in each group box, so there are a total of three event handler methods, one each for grpAppearance, grpCheckAlign, and grpTextAlign.

Each of the three event handlers uses a different technique for implementing the event handler, although in practice you will probably find the middle method, rdoCheckAlign_CheckedChanged, the most efficient.

The first event handler, rdoAppearance_CheckedChanged, capitalizes on the fact that there are only two radio buttons in the group, and therefore only two possible outcomes. This lends itself to a simple if-else (if...then...else) construct. Within each statement block, the Controls collection of the Panel control is iterated to apply the appropriate value of the Appearance property to the checkboxes.

The second event handler, rdoCheckAlign_CheckedChanged, uses the fact that the Tag property of the radio buttons is set to the appropriate value of the ContentAlignment enumeration. The object raising the CheckedChanged event (i.e., the radio button that has been changed) is cast to a variable of type RadioButton, and then in the iteration of the CheckBox controls, that Tag value is cast back to the ContentAlignment type and assigned to the CheckAlign property of each CheckBox control.

The third event handler, rdoTextAlign_CheckedChanged, uses a switch statement (select case in VB.NET) to apply the correct value of the ContentAlignment enumeration to the checkboxes. There is a slight difference here between the C# and VB.NET versions of the code. Since the switch construct in C# requires either an integer or string expression to switch on, it is not possible to switch directly on the Tag value, which is of type ContentAlignment, as is done in the VB.NET code. Instead the C# version must cast the ContentAlignment enumeration to its equivalent integer value and switch on that.

Windows Forms and the .NET Framework

Getting Started

Visual Studio .NET

Events

Windows Forms

Dialog Boxes

Controls: The Base Class

Mouse Interaction

Text and Fonts

Drawing and GDI+

Labels and Buttons

Text Controls

Other Basic Controls

TreeView and ListView

List Controls

Date and Time Controls

Custom Controls

Menus and Bars

ADO.NET

Updating ADO.NET

Exceptions and Debugging

Configuration and Deployment



Programming. NET Windows Applications
Programming .Net Windows Applications
ISBN: 0596003218
EAN: 2147483647
Year: 2003
Pages: 148

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