Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Visual CSharp 2005 Recipes (2006) [eng]

.pdf
Скачиваний:
48
Добавлен:
16.08.2013
Размер:
4.04 Mб
Скачать

228 C H A P T E R 7 W I N D O W S F O R M S

protected override void OnClosing(CancelEventArgs e)

{

//Call the OnClosing method of the base class to ensure the

//FormClosing event is raised correctly. base.OnClosing(e);

//Update the application settings for Form. Settings.Default.Size = this.Size;

//Store all application settings.

Settings.Default.Save();

}

[STAThread]

public static void Main(string[] args)

{

Application.Run(new Recipe07_06());

}

}

}

7-7. Force a List Box to Scroll to the Most Recently Added Item

Problem

You need to scroll a list box programmatically so that the most recently added items are visible.

Solution

Set the ListBox.TopIndex property, which sets the first visible list item.

How It Works

In some cases, you might have a list box that stores a significant amount of information or one that you add information to periodically. Often, the most recent information, which is added at the end of the list, is more important than the information at the top of the list. One solution is to scroll the list box so that recently added items are visible. The ListBox.TopIndex property enables you to do this by allowing you to specify which item is visible at the top of the list.

The Code

The following sample form includes a list box and a button. Each time the button is clicked, 20 items are added to the list box. Each time new items are added, the code sets the ListBox.TopIndex property and forces the list box to display the most recently added items. To provide better feedback, the same line is also selected.

using System;

using System.Windows.Forms;

C H A P T E R 7 W I N D O W S F O R M S

229

namespace Apress.VisualCSharpRecipes.Chapter07

{

public partial class Recipe07_07 : Form

{

//A counter to keep track of the number of items added

//to the ListBox.

private int counter = 0;

public Recipe07_07()

{

//Initialization code is designer generated and contained

//in a separate file using the C# 2.0 support for partial

//classes.

InitializeComponent();

}

// Button click event handler adds 20 new items to the ListBox. private void cmdTest_Click(object sender, EventArgs e)

{

// Add 20 items.

for (int i = 0; i < 20; i++)

{

counter++;

listBox1.Items.Add("Item " + counter.ToString());

}

//Set the TopIndex property of the ListBox to ensure the

//most recently added items are visible. listBox1.TopIndex = listBox1.Items.Count - 1; listBox1.SelectedIndex = listBox1.Items.Count - 1;

}

[STAThread]

public static void Main(string[] args)

{

Application.Run(new Recipe07_07());

}

}

}

7-8. Restrict a Textbox to Accepting Only Specific Input

Problem

You need to create a textbox that will reject all nonnumeric keystrokes.

Solution

Use the MaskedTextBox control and set the Mask property to configure the input that is acceptable.

230 C H A P T E R 7 W I N D O W S F O R M S

How It Works

One way to ensure user input is valid is to prevent invalid data from being entered in the first place. The MaskedTextBox control facilitates this approach. The MaskedTextBox.Mask property takes a string that specifies the input mask for the control. This mask determines what type of input a user can enter at each point in the control’s text area. If the user enters an incorrect character, the control will beep if the BeepOnError property is true, and the MaskInputRejected event is raised so that you can customize the handling of incorrect input.

Note The MaskedTextBox control will not solve all your user-input validation problems. While it does make some types of validation easy to implement, without customization, it will not ensure some common validation requirements are met. For example, you can specify that only numeric digits can be input, but you cannot specify that they must be less than a specific value, nor can you control the overall characteristics of the input value.

The Code

The following example demonstrates the use of the MaskedTextBox control. A series of buttons allows you to change the active mask on the MaskedTextBox control and experiment with the various masks. Notice that the control tries to accommodate existing content with the new mask when the mask is changed. If the content is not allowed with the new mask, the control is cleared.

using System;

using System.Threading; using System.Windows.Forms;

namespace Apress.VisualCSharpRecipes.Chapter07

{

public partial class Recipe07_08 : Form

{

public Recipe07_08()

{

//Initialization code is designer generated and contained

//in a separate file using the C# 2.0 support for partial

//classes.

InitializeComponent();

}

private void btnTime_Click(object sender, EventArgs e)

{

// Set the input mask to that of a short time. this.mskTextBox.UseSystemPasswordChar = false; this.mskTextBox.Mask = "00:00"; this.lblActiveMask.Text = this.mskTextBox.Mask; this.mskTextBox.Focus();

}

private void btnUSZip_Click(object sender, EventArgs e)

{

// Set the input mask to that of a US ZIP code. this.mskTextBox.UseSystemPasswordChar = false; this.mskTextBox.Mask = "00000-9999"; this.lblActiveMask.Text = this.mskTextBox.Mask; this.mskTextBox.Focus();

}

C H A P T E R 7 W I N D O W S F O R M S

231

private void btnUKPost_Click(object sender, EventArgs e)

{

// Set the input mask to that of a UK postcode. this.mskTextBox.UseSystemPasswordChar = false; this.mskTextBox.Mask = ">LCCC 9LL"; this.lblActiveMask.Text = this.mskTextBox.Mask; this.mskTextBox.Focus();

}

private void btnCurrency_Click(object sender, EventArgs e)

{

// Set the input mask to that of a currency. this.mskTextBox.UseSystemPasswordChar = false; this.mskTextBox.Mask = "$999,999.00"; this.lblActiveMask.Text = this.mskTextBox.Mask; this.mskTextBox.Focus();

}

private void btnDate_Click(object sender, EventArgs e)

{

// Set the input mask to that of a short date. this.mskTextBox.UseSystemPasswordChar = false; this.mskTextBox.Mask = "00/00/0000"; this.lblActiveMask.Text = this.mskTextBox.Mask; this.mskTextBox.Focus();

}

private void btnSecret_Click(object sender, EventArgs e)

{

// Set the input mask to that of a secret PIN. this.mskTextBox.UseSystemPasswordChar = true; this.mskTextBox.Mask = "0000"; this.lblActiveMask.Text = this.mskTextBox.Mask; this.mskTextBox.Focus();

}

[STAThread]

public static void Main(string[] args)

{

Application.Run(new Recipe07_08());

}

}

}

Notes

The MaskedTextBox used in this recipe is new to .NET Framework 2.0. In previous versions of the

.NET Framework, one approach was to use a standard TextBox control and handle the KeyPress events it raises. The KeyPress event is raised after each keystroke has been received but before it is displayed. You can use the KeyPressEventArgs event parameter to effectively cancel an invalid keystroke by setting its Handled property to true.

For example, to allow only numeric input, you must allow a keystroke only if it corresponds to a number (0 through 9) or a special control key (such as Delete or the arrow keys). The keystroke character is provided to the KeyPress event through the KeyPressEventArgs.KeyChar property. You can use two static methods of the System.Char class—IsDigit and IsControl—to quickly test the character.

232 C H A P T E R 7 W I N D O W S F O R M S

7-9. Use an Autocomplete Combo Box

Problem

You want to create a combo box that automatically completes what the user is typing based on the item list.

Solution

You can implement a basic autocomplete combo box by creating a custom control that overrides the OnKeyPress and OnTextChanged methods of the ComboBox object.

Note The ComboBox control in .NET Framework 2.0 provides autocomplete options. You can configure the behavior using the AutoCompleteMode property of the ComboBox class.

How It Works

An autocomplete control has many different variations. For example, the control may fill in values based on a list of recent selections (as Microsoft Excel does when you are entering cell values), or the control might display a drop-down list of near matches (as Microsoft Internet Explorer does when you are typing a URL). You can create a basic autocomplete combo box by handling the KeyPress and TextChanged events, or by creating a custom class that derives from ComboBox and overrides the

OnKeyPress and OnTextChanged methods.

The Code

The following example contains an AutoCompleteComboBox control that derives from ComboBox. The AutoCompleteComboBox control supports autocompletion by overriding the OnKeyPress and OnTextChanged inherited methods. In the OnKeyPress method, the combo box determines whether or not an autocomplete replacement should be made. If the user pressed a character key (such as a letter), the replacement can be made, but if the user pressed a control key (such as the backspace key, the cursor keys, and so on), no action should be taken. The OnTextChanged method performs the actual replacement after the key processing is complete. This method looks up the first match for the current text in the list of items, and then adds the rest of the matching text. After the text is added,

the combo box selects the characters between the current insertion point and the end of the text. This allows the user to continue typing and replace the autocomplete text if it is not what the user wants.

using System;

using System.Windows.Forms;

namespace Apress.VisualCSharpRecipes.Chapter07

{

public class AutoCompleteComboBox : ComboBox

{

//A private member to track if a special key is pressed, in

//which case, any text replacement operation will be skipped. private bool controlKey = false;

//Determine whether a special key was pressed.

protected override void OnKeyPress(System.Windows.Forms.KeyPressEventArgs e)

{

C H A P T E R 7 W I N D O W S F O R M S

233

//First call the overridden base class method. base.OnKeyPress(e);

//Clear the text if the Escape key is pressed. if (e.KeyChar == (int)Keys.Escape)

{

//Clear the text.

this.SelectedIndex = -1; this.Text = ""; controlKey = true;

}

//Don't try to autocomplete when control key is pressed. else if (Char.IsControl(e.KeyChar))

{

controlKey = true;

}

//Noncontrol keys should trigger autocomplete.

else

{

controlKey = false;

}

}

// Perform the text substitution.

protected override void OnTextChanged(System.EventArgs e)

{

// First call the overridden base class method. base.OnTextChanged(e);

if (this.Text != "" && !controlKey)

{

//Search the current contents of the combo box for a

//matching entry.

string matchText = this.Text;

int match = this.FindString(matchText);

// If a matching entry is found, insert it now. if (match != -1)

{

this.SelectedIndex = match;

//Select the added text so it can be replaced

//if the user keeps typing. this.SelectionStart = matchText.Length;

this.SelectionLength = this.Text.Length - this.SelectionStart;

}

}

}

}

}

Usage

The following code demonstrates the use of the AutoCompleteComboBox by adding it to a form and filling it with a list of words. In this example, the control is added to the form manually, and the list of words is retrieved from a text file named words.txt. As an alternative, you could compile the

234C H A P T E R 7 W I N D O W S F O R M S

AutoCompleteComboBox class to a separate class library assembly, and then add it to the Visual Studio Toolbox, so you could add it to forms at design time.

using System; using System.IO;

using System.Drawing; using System.Windows.Forms;

namespace Apress.VisualCSharpRecipes.Chapter07

{

public partial class Recipe07_09 : Form

{

public Recipe07_09()

{

//Initialization code is designer generated and contained

//in a separate file using the C# 2.0 support for partial

//classes.

InitializeComponent();

}

protected override void OnLoad(EventArgs e)

{

//Call the OnLoad method of the base class to ensure the Load

//event is raised correctly.

base.OnLoad(e);

//Add the AutoCompleteComboBox to the form. AutoCompleteComboBox combo = new AutoCompleteComboBox(); combo.Location = new Point(10, 10); this.Controls.Add(combo);

//Read the list of words from the file words.txt and add them

//to the AutoCompleteComboBox.

using (FileStream fs = new FileStream("words.txt", FileMode.Open))

{

using (StreamReader r = new StreamReader(fs))

{

while (r.Peek() > -1)

{

string word = r.ReadLine(); combo.Items.Add(word);

}

}

}

}

[STAThread]

public static void Main(string[] args)

{

Application.Run(new Recipe07_09());

}

}

}

Figure 7-5 shows how the AutoCompleteComboBox will look when the Recipe07-09 example is run.

C H A P T E R 7 W I N D O W S F O R M S

235

Figure 7-5. An autocomplete combo box

7-10. Sort a List View by Any Column

Problem

You need to sort a list view, but the built-in ListView.Sort method sorts based on only the first column.

Solution

Create a type that implements the System.Collections.IComparer interface and can sort ListViewItem objects. The IComparer type can sort based on any ListViewItem criteria you specify. Set the ListView. ListViewItemSorter property with an instance of the IComparer type before calling the ListView.Sort method.

How It Works

The ListView control provides a Sort method that orders items alphabetically based on the text in the first column. If you want to sort based on other column values or order items numerically, you need to create a custom implementation of the IComparer interface that can perform the work. The IComparer interface defines a single method named Compare, which takes two object arguments and determines which one should be ordered first. Full details of how to implement the IComparer interface are available in recipe 13-3.

The Code

The following example demonstrates the creation of an IComparer implementation named ListViewItemComparer. The ListViewItemComparer class also implements two additional properties: Column and Numeric. The Column property identifies the column that should be used for sorting. The Numeric property is a Boolean flag that can be set to true if you want to perform number-based comparisons instead of alphabetic comparisons.

When the user clicks a column heading, the example creates a ListViewItemComparer instance, configures the column to use for sorting, and assigns the ListViewItemComparer instance to the

ListView.ListViewItemSorter property before calling the ListView.Sort method.

using System;

using System.Collections; using System.Windows.Forms;

namespace Apress.VisualCSharpRecipes.Chapter07

{

public partial class Recipe07_10 : Form

236 C H A P T E R 7 W I N D O W S F O R M S

{

public Recipe07_10()

{

//Initialization code is designer generated and contained

//in a separate file using the C# 2.0 support for partial

//classes.

InitializeComponent();

}

// Event handler to handle user clicks on column headings.

private void listView1_ColumnClick(object sender, ColumnClickEventArgs e)

{

//Create and/or configure the ListViewItemComparer to sort based on

//the column that was clicked.

ListViewItemComparer sorter = listView1.ListViewItemSorter as ListViewItemComparer;

if (sorter == null)

{

// Create a new ListViewItemComparer. sorter = new ListViewItemComparer(e.Column); listView1.ListViewItemSorter = sorter;

}

else

{

// Configure the existing ListViewItemComparer. sorter.Column = e.Column;

}

// Sort the ListView listView1.Sort();

}

[STAThread]

public static void Main(string[] args)

{

Application.Run(new Recipe07_10());

}

}

public class ListViewItemComparer : IComparer

{

//Private members to configure comparer logic. private int column;

private bool numeric = false;

//Property to get/set the column to use for comparison. public int Column

{

get { return column; } set { column = value; }

}

//Property to get/set whether numeric comparison is required

//as opposed to the standard alphabetic comparison.

public bool Numeric

C H A P T E R 7 W I N D O W S F O R M S

237

{

get { return numeric; } set { numeric = value; }

}

public ListViewItemComparer(int columnIndex)

{

Column = columnIndex;

}

public int Compare(object x, object y)

{

//Convert the arguments to ListViewItem objects. ListViewItem itemX = x as ListViewItem; ListViewItem itemY = y as ListViewItem;

//Handle logic for null reference as dictated by the

//IComparer interface. Null is considered less than

//any other value.

if (itemX == null && itemY == null) return 0; else if (itemX == null) return -1;

else if (itemY == null) return 1;

//Short-circuit condition where the items are references

//to the same object.

if (itemX == itemY) return 0;

// Determine if numeric comparison is required. if (Numeric)

{

//Convert column text to numbers before comparing.

//If the conversion fails, just use the value 0. decimal itemXVal, itemYVal;

if (!Decimal.TryParse(itemX.SubItems[Column].Text, out itemXVal))

{

itemXVal = 0;

}

if (!Decimal.TryParse(itemY.SubItems[Column].Text, out itemYVal))

{

itemYVal = 0;

}

return Decimal.Compare(itemXVal, itemYVal);

}

else

{

//Keep the column text in its native string format

//and perform an alphabetic comparison.

string itemXText = itemX.SubItems[Column].Text; string itemYText = itemY.SubItems[Column].Text;

return String.Compare(itemXText, itemYText);

}

}

}

}

Соседние файлы в предмете Программирование на C++