
Pro CSharp And The .NET 2.0 Platform (2005) [eng]
.pdf


636 CHAPTER 19 ■ BUILDING A BETTER WINDOW WITH SYSTEM.WINDOWS.FORMS
For this example, you will leverage the new item drop-down editor. Add two new
ToolStripStatusLabel types named toolStripStatusLabelMenuState and toolStripStatusLabelClock, and a ToolStripDropDownButton named toolStripDropDownButtonDateTime. As you would expect, this will add new member variables in the *.Designer.cs file and update InitializeComponent() accordingly. Note that the StatusStrip maintains an internal collection to hold each of the panes:
partial class MainForm
{
private void InitializeComponent()
{
...
//
// mainStatusStrip
//
this.mainStatusStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.toolStripStatusLabelMenuState,
this.toolStripStatusLabelClock,
this.toolStripDropDownButtonDateTime});
...
}
private System.Windows.Forms.StatusStrip mainStatusStrip; private System.Windows.Forms.ToolStripStatusLabel
toolStripStatusLabelMenuState;
private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabelClock;
private System.Windows.Forms.ToolStripDropDownButton toolStripDropDownButtonDateTime;
...
}
Now, select the ToolStripDropDownButton on the designer and add two new menu items named currentTimeToolStripMenuItem and dayoftheWeekToolStripMenuItem (see Figure 19-19).
Figure 19-19. Adding menu items to the ToolStripDropDownButton
To configure your panes to reflect the look and feel shown in Figure 19-19, you will need to set several properties, which you do using the Visual Studio 2005 Properties window. Table 19-12 documents the necessary properties to set and events to handle for each item on your StatusStrip (of course, feel free to stylize the panes with additional settings as you see fit).

|
CHAPTER 19 ■ BUILDING A BETTER WINDOW WITH SYSTEM.WINDOWS.FORMS |
637 |
|
Table 19-12. StatusStrip Pane Configuration |
|
|
|
|
|
|
|
Pane Member Variable |
Properties to Set |
Events to Handle |
|
toolStripStatusLabelMenuState |
Spring = true |
None |
|
|
Text = (empty) |
|
|
|
TextAlign = TopLeft |
|
|
toolStripStatusLabelClock |
BorderSides = All |
None |
|
|
Text = (empty) |
|
|
toolStripDropDownButtonDateTime |
Image = (see text that follows) |
None |
|
dayoftheWeekToolStripMenuItem |
Text = “Day of the Week” |
MouseHover |
|
|
|
Click |
|
currentTimeToolStripMenuItem |
Text = “Current Time” |
MouseHover |
|
|
|
Click |
|
|
|
|
|
The Image property of the toolStripDropDownButtonDateTime member can be set to any image file on your machine (of course, extremely large image files will be quite skewed). For this example, you may wish to use the happyDude.bmp file included with this book’s downloadable source code (please visit the Downloads section of the Apress website, http://www.apress.com).
So at this point, the GUI design is complete! Before you implement the remaining event handlers, you need to get to know the role of the Timer component.
Working with the Timer Type
Recall that the second pane should display the current time or current date based on user preference. The first step to take to achieve this design goal is to add a Timer member variable to the Form. A Timer is a component that calls some method (specified using the Tick event) at a given interval (specified by the Interval property).
Drag a Timer component onto your Forms designer and rename it to timerDateTimeUpdate. Using the Properties window, set the Interval property to 1,000 (the value in milliseconds) and set the Enabled property to true. Finally, handle the Tick event. Before implementing the Tick event handler, define a new enum type in your project named DateTimeFormat. This enum will be used to determine whether the second ToolStripStatusLabel should display the current time or the current day of the week:
enum DateTimeFormat
{
ShowClock, ShowDay
}
With this enum in place, update your MainWindow with the following code:
public partial class MainWindow : Form
{
// Which format to display?
DateTimeFormat dtFormat = DateTimeFormat.ShowClock;
...
private void timerDateTimeUpdate_Tick(object sender, EventArgs e)
{
string panelInfo = "";
// Create current format.
if (dtFormat == DateTimeFormat.ShowClock) panelInfo = DateTime.Now.ToLongTimeString();

638 CHAPTER 19 ■ BUILDING A BETTER WINDOW WITH SYSTEM.WINDOWS.FORMS
else
panelInfo = DateTime.Now.ToLongDateString();
// Set text on pane. toolStripStatusLabelClock.Text = panelInfo;
}
}
Notice that the Timer event handler makes use of the DateTime type. Here, you simply find the current system time or date using the Now property and use it to set the Text property of the toolStripStatusLabelClock member variable.
Toggling the Display
At this point, the Tick event handler should be displaying the current time within the toolStripStatusLabelClock pane, given that the default value of your DateTimeFormat member variable as been set to DateTimeFormat.ShowClock. To allow the user to toggle between the date and time display, update your MainWindow as so (note you are also toggling which of the two menu items in the ToolStripDropDownButton should be checked):
public partial class MainWindow : Form
{
// Which format to display?
DateTimeFormat dtFormat = DateTimeFormat.ShowClock;
// Marks the item checked.
private ToolStripMenuItem currentCheckedItem;
public MainWindow()
{
InitializeComponent();
//These properties can also be set
//with the Properties window.
Text = "Status Strip Example"; CenterToScreen();
BackColor = Color.CadetBlue;
currentCheckedItem = currentTimeToolStripMenuItem; currentCheckedItem.Checked = true;
}
...
private void currentTimeToolStripMenuItem_Click(object sender, EventArgs e)
{
// Toggle check mark and set pane format to time. currentCheckedItem.Checked = false;
dtFormat = DateTimeFormat.ShowClock; currentCheckedItem = currentTimeToolStripMenuItem; currentCheckedItem.Checked = true;
}
private void dayoftheWeekToolStripMenuItem_Click(object sender, EventArgs e)
{
// Toggle check mark and set pane format to date. currentCheckedItem.Checked = false;
dtFormat = DateTimeFormat.ShowDay; currentCheckedItem = dayoftheWeekToolStripMenuItem; currentCheckedItem.Checked = true;
}
}

CHAPTER 19 ■ BUILDING A BETTER WINDOW WITH SYSTEM.WINDOWS.FORMS |
639 |
Displaying the Menu Selection Prompts
Finally, you need to configure the first pane to hold menu help strings. As you know, most applications send a small bit of text information to the first pane of a status bar whenever the end user selects a menu item (e.g., “This terminates the application”). Given that you have already handled the MouseHover events for each submenu on the MenuStrip and TooStripDropDownButton, all you need to do is assign a proper value to the Text property for the toolStripStatusLabelMenuState member variable, for example:
private void exitToolStripMenuItem_MouseHover(object sender, EventArgs e) { toolStripStatusLabelMenuState.Text = "Exits the app."; }
private void aboutToolStripMenuItem_MouseHover(object sender, EventArgs e) { toolStripStatusLabelMenuState.Text = "Shows about box."; }
private void dayoftheWeekToolStripMenuItem_MouseHover(object sender, EventArgs e) { toolStripStatusLabelMenuState.Text = "Shows the day of the week."; }
private void currentTimeToolStripMenuItem_MouseHover(object sender, EventArgs e) { toolStripStatusLabelMenuState.Text = "Shows the current time."; }
Take your updated project out for a test drive. You should now be able to find these informational help strings in the first pane of your StatusStrip as you select each menu item.
Establishing a “Ready” State
The final thing to do for this example is ensure that when the user deselects a menu item, the first text pane is set to a default message (e.g., “Ready”). With the current design, the previously selected menu prompt remains on the leftmost text pane, which is confusing at best. To rectify this issue, handle the MouseLeave event for the Exit, About, Day of the Week, and Current Time menu items. However, rather than generating a new event handler for each item, have them all call a method named SetReadyPrompt():
private void SetReadyPrompt(object sender, EventArgs e)
{toolStripStatusLabelMenuState.Text = "Ready."; }
With this, you should find that the first pane resets to this default message as soon as the mouse cursor leaves any of your four menu items.
■Source Code The StatusBarApp project is included under the Chapter 19 subdirectory.
Working with ToolStrips
The next Form-level GUI item to examine in this chapter is the .NET 2.0 ToolStrip type, which overshadows the functionality found within the depreciated .NET 1.x ToolBar class. As you know, toolbars typically provide an alternate means to activate a given menu item. Thus, if the user clicks a Save button, this has the same effect as selecting File Save. Much like MenuStrip and StatusStrip, the ToolStrip type can contain numerous toolbar items, some of which you have already encountered in previous examples:
•ToolStripButton
•ToolStripLabel
•ToolStripSplitButton

640CHAPTER 19 ■ BUILDING A BETTER WINDOW WITH SYSTEM.WINDOWS.FORMS
•ToolStripDropDownButton
•ToolStripSeparator
•ToolStripComboBox
•ToolStripTextBox
•ToolStripProgressBar
Like other Windows Forms controls, the ToolStrip supports an inline editor that allows you to quickly add standard button types (File, Exit, Help, Copy, Paste, etc.) to a ToolStrip, change the docking position, and embed the ToolStrip in a ToolStripContainer (more details in just a bit). Figure 19-20 illustrates the designer support for ToolStrips.
Figure 19-20. Designing ToolStrips
Like MenuStrips and StatusStrips, individual ToolStrip controls are added to the ToolStrip’s internal collection via the Items property. If you click the Insert Standard Items link on the inline ToolStrip editor, your InitializeComponent() method is updated to insert an array of ToolStripItem- derived types that represent each item:
private void InitializeComponent()
{
...
// Autogenerated code to prep a ToolStrip. this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.newToolStripButton, this.openToolStripButton, this.saveToolStripButton, this.printToolStripButton, this.toolStripSeparator, this.cutToolStripButton, this.copyToolStripButton, this.pasteToolStripButton, this.toolStripSeparator1, this.helpToolStripButton});
...
}


■ BUILDING A BETTER WINDOW WITH SYSTEM.WINDOWS.FORMS

CHAPTER 19 ■ BUILDING A BETTER WINDOW WITH SYSTEM.WINDOWS.FORMS |
643 |
Text = string.Format("Your Font size is: {0}", currFontSize); Invalidate();
}
private void toolStripButtonGrowFont_Click(object sender, EventArgs e)
{
// Increase font size by 5 and refresh display. currFontSize += 5;
if (currFontSize >= MaxFontSize) currFontSize = MaxFontSize;
Text = string.Format("Your Font size is: {0}", currFontSize); Invalidate();
}
private void MainWindow_Paint(object sender, PaintEventArgs e)
{
// Paint the user-defined message.
Graphics g = e.Graphics; g.DrawString(toolStripTextBoxMessage.Text,
new Font("Times New Roman", currFontSize), Brushes.Black, 10, 60);
}
}
As a final enhancement, if you wish to ensure that the user message is updated as soon as the ToolStripTextBox loses focus, you can handle the LostFocus event and Invalidate() your Form within the generated event handler:
public partial class MainWindow : Form
{
...
public MainWindow()
{
...
this.toolStripTextBoxMessage.LostFocus
+= new EventHandler(toolStripTextBoxMessage_LostFocus);
}
void toolStripTextBoxMessage_LostFocus(object sender, EventArgs e)
{
Invalidate();
}
...
}
Working with ToolStripContainers
ToolStrips, if required, can be configured to be “dockable” against any or all sides of the Form that contains it. To illustrate how you can accomplish this, right-click your current ToolStrip using the designer and select the Embed in ToolStripContainer menu option. Once you have done so, you will find that the ToolStrip has been contained within a ToolStripContainer. For this example, select the Dock Fill in Form option (see Figure 19-23).