Preview TextBox changes in C#, Part 2

Part 1 of this post explained how the example previews changes made by keyboard events. It then accepts or cancels the changes depending on whether the TextBox control’s new value is a valid integer (or the start of one as in ” “, “-“, or “+”). This post explains how the example handles the TextBox control’s context menu.

By default the TextBox provides a context menu that provides a bunch of commands including Undo, Copy, Cut, Paste, and Delete. All of these can change the control’s value.

Although you cannot intercept the TextBox control’s context menu, you can disable it or replace it with a context menu of your own. To disable the context menu, see Remove a TextBox control’s context menu in C#.

This post uses the second approach.

At design time, I added a ContextMenuStrip to the form and gave it the menu items Undo, Copy, Cut, Paste, and Delete as shown in the picture. You could assign the menu to the TextBox control’s ContextMenuStrip property at run time, but in order to simplify design time setup I made that assignment in the following Form_Load event handler.

// Attach the TextBox's ContextMenuStrip.
private void Form1_Load(object sender, EventArgs e)
{
    txtInteger.ContextMenuStrip = ctxTextBox;
}

The following code shows how the menu’s commands work.

// Make context menu items to do the
// same work as the control characters.
private void ctxUndo_Click(object sender, EventArgs e)
{
    txtInteger.Undo();
}
private void ctxCopy_Click(object sender, EventArgs e)
{
    Clipboard.Clear();
    Clipboard.SetText(txtInteger.SelectedText);
}
private void ctxCut_Click(object sender, EventArgs e)
{
    ShouldCancelTextBoxEvent(txtInteger,
        EditType.Cut, ' ', true);
}
private void ctxPaste_Click(object sender, EventArgs e)
{
    ShouldCancelTextBoxEvent(txtInteger,
        EditType.Paste, ' ', true);
}
private void ctxDelete_Click(object sender, EventArgs e)
{
    ShouldCancelTextBoxEvent(txtInteger,
        EditType.Delete, ' ', true);
}

These are fairly straightforward. Several of them use the ShouldCancelTextBoxEvent method described in the previous post. That method validates the change and beeps if a change is invalid.

Notice that final argument passed to ShouldCancelTextBoxEvent in this code is true. That value tells ShouldCancelTextBoxEvent that it should update the TextBox control’s value if the change is valid so the menu commands can do their jobs. (Recall that when the keyboard event handlers call ShouldCancelTextBoxEvent, they set this final argument to false so the keyboard events can make changes if they are valid. There are no similar keyboard events when the context menu commands execute.)

The only remaining piece to this example is the following event handler that executes when the context menu is opening.

// Enable appropriate context menu items.
private void ctxTextBox_Opening(object sender, CancelEventArgs e)
{
    ctxUndo.Enabled = txtInteger.CanUndo;

    // Copy and Cut are enabled if anything is selected.
    ctxCopy.Enabled = (txtInteger.SelectionLength > 0);
    ctxCut.Enabled = (txtInteger.SelectionLength > 0);

    // Delete is enabled if anything is selected or there
    // is a character after the insertion point to delete.
    ctxDelete.Enabled =
        ((txtInteger.SelectionLength > 0) ||
         (txtInteger.SelectionStart < txtInteger.Text.Length));

    // Paste is enabled if the clipboard contains text.
    ctxPaste.Enabled = Clipboard.ContainsText();
}

This code enables and disables the appropriate context menu commands depending on what is selected in the TextBox. For example, the Copy and Cut commands are enabled only if some text is selected in the TextBox.

The only command that is a bit uncertain here is Paste because it might end up creating an invalid value, which would then be prohibited. For example, if the clipboard contains the text "ten" and you try to paste it into the TextBox, the ShouldCancelTextBoxEvent method prevents it and beeps.

If you wanted to you could make the ctxTextBox_Opening event handler evaulate the potential result of the paste and disable that command if the result would be invalid. I decided it was better to let the user try to paste and get a beep instead of wondering why Paste was disabled when there was text in the clipboard. This version is also simpler, but you can change it if you like.

Note that you could have a similar issue with the Cut command, at least if you're looking for floating point values instead of integers. For example, suppose the TextBox holds the value -1.2E-10 and the "1.2E" is highlighted. In that case using Cut would make the value "--10" and that's not a valid floating point value.

This example makes the user enter only integers in a TextBox. My next post will show how to make the user enter only floating point values.


Download Example   Follow me on Twitter   RSS feed   Donate




This entry was posted in controls, user interface and tagged , , , , , , , , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *