TX Text Control .NET for Windows Forms

Integrating Existing Menus and Toolbars

Topic

Many Windows Forms applications already have a MenuStrip and a ToolStrip when a word processor is added to them. Their items can drive the TextControl directly: each item calls a method of the editor, and a few event handlers keep the enabled and checked states in step with the text. What follows builds an Edit menu, a Format menu and a formatting toolbar for an existing form, and shows how the keyboard shortcuts of the menus fit together with the keys the editor handles itself.

If you start a new form instead, the ready-made bars of TX Text Control may serve better: the ButtonBar, the rulers and the status bar are described in Add Rulers, Toolbars, and a Status Bar, and the ribbon tabs in Built-in Ribbon Tabs. Both can also be combined with your own menus.

How Menu Items Reach the Editor

The TextControl has a method for each command a word processor menu offers, and the menu items of Windows Forms call these methods from their Click events:

Menu itemMethodEnabled when
Undo, RedoUndo, RedoCanUndo, CanRedo
CutCutCanCopy and CanEdit
CopyCopyCanCopy
PastePasteCanPaste
FindFindAlways
Font, ParagraphFontDialog, ParagraphFormatDialogAlways
PrintPrintCanPrint

The dialog methods open the built-in dialog boxes of TX Text Control; Built-in Dialog Boxes lists all of them. Formatting that a toolbar button toggles, such as bold or italic text, is set through the Selection, which stands for the selected text or, when nothing is selected, the input position. When the selected text has no common value for an attribute, the property returns its default value, for example false for Bold.

Add the Menus and the Toolbar

In the designer of Form1, next to the TextControl named textControl1:

  1. In the MenuStrip, add a menu item named editToolStripMenuItem with the text &Edit and the items undoToolStripMenuItem, redoToolStripMenuItem, cutToolStripMenuItem, copyToolStripMenuItem, pasteToolStripMenuItem and findToolStripMenuItem.
  2. Add a menu item F&ormat with the items fontToolStripMenuItem and paragraphToolStripMenuItem.
  3. In the ToolStrip, add two buttons named boldToolStripButton and italicToolStripButton with the texts B and I, and a ToolStripComboBox named fontToolStripComboBox.

The designer creates the fields; the code below connects them in the constructor, so no event has to be set in the Properties window.

Write the Code

The following Form1.cs connects the items, fills the font list and updates the states. Keep the namespace Visual Studio created for your project:

using System;
using System.Windows.Forms;

namespace MyWinFormsApp
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            Load += Form1_Load;

            // Edit menu
            editToolStripMenuItem.DropDownOpening += EditToolStripMenuItem_DropDownOpening;
            undoToolStripMenuItem.Click += (s, e) => textControl1.Undo();
            redoToolStripMenuItem.Click += (s, e) => textControl1.Redo();
            cutToolStripMenuItem.Click += (s, e) => textControl1.Cut();
            copyToolStripMenuItem.Click += (s, e) => textControl1.Copy();
            pasteToolStripMenuItem.Click += (s, e) => textControl1.Paste();
            findToolStripMenuItem.Click += (s, e) => textControl1.Find();

            // Format menu
            fontToolStripMenuItem.Click += (s, e) => textControl1.FontDialog();
            paragraphToolStripMenuItem.Click += (s, e) => textControl1.ParagraphFormatDialog();

            // Toolbar
            boldToolStripButton.Click += BoldToolStripButton_Click;
            italicToolStripButton.Click += ItalicToolStripButton_Click;
            fontToolStripComboBox.SelectedIndexChanged += FontToolStripComboBox_SelectedIndexChanged;

            // Keep the toolbar in step with the text
            textControl1.InputPositionChanged += (s, e) => UpdateToolbar();
            textControl1.CharFormatChanged += (s, e) => UpdateToolbar();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            // The list of fonts is available once the control is initialized
            fontToolStripComboBox.Items.AddRange(textControl1.GetSupportedFonts());
            UpdateToolbar();
        }

        private void EditToolStripMenuItem_DropDownOpening(object sender, EventArgs e)
        {
            // Enable only what the editor can do right now
            undoToolStripMenuItem.Enabled = textControl1.CanUndo;
            redoToolStripMenuItem.Enabled = textControl1.CanRedo;
            cutToolStripMenuItem.Enabled = textControl1.CanCopy && textControl1.CanEdit;
            copyToolStripMenuItem.Enabled = textControl1.CanCopy;
            pasteToolStripMenuItem.Enabled = textControl1.CanPaste;
        }

        private void BoldToolStripButton_Click(object sender, EventArgs e)
        {
            textControl1.Selection.Bold = !textControl1.Selection.Bold;
            textControl1.Focus();
        }

        private void ItalicToolStripButton_Click(object sender, EventArgs e)
        {
            textControl1.Selection.Italic = !textControl1.Selection.Italic;
            textControl1.Focus();
        }

        private void FontToolStripComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (fontToolStripComboBox.SelectedItem is string fontName
                && fontName != textControl1.Selection.FontName)
            {
                textControl1.Selection.FontName = fontName;
                textControl1.Focus();
            }
        }

        private void UpdateToolbar()
        {
            TXTextControl.Selection selection = textControl1.Selection;
            boldToolStripButton.Checked = selection.Bold;
            italicToolStripButton.Checked = selection.Italic;
            fontToolStripComboBox.Text = selection.FontName;
        }
    }
}

The code works as follows:

  • The Click handlers call one method each. FontDialog and ParagraphFormatDialog return a DialogResult, which you can check when the application has to know whether the user clicked OK.
  • DropDownOpening occurs just before the Edit menu opens. The Can... properties say at that moment whether there is something to undo, redo, copy or paste, so the items never offer a command that does nothing. Cut also checks CanEdit, because cutting removes text, which a read-only or protected document doesn't allow. Clipboard Operations and Undo and Redo describe these properties in detail.
  • The toolbar buttons read and set Selection.Bold and Selection.Italic, and the combo box Selection.FontName. Focus returns the keyboard focus to the editor, so the user goes on typing.
  • InputPositionChanged occurs when the input position moves, and CharFormatChanged when the character formatting of the selection or the input position changes. Both call UpdateToolbar, which checks the buttons and shows the font where the user is typing.
  • GetSupportedFonts returns null until the control is completely initialized, so the list is filled in the Load event of the form.

Run the application, select a word and click B: the word turns bold, and the button is checked whenever the caret is in bold text. The Edit menu offers Paste only when the clipboard holds a format the editor can paste and the document may be changed.

Bind Instead of Handling Events

The states of a toolbar can also come from data binding. A CheckBox with the Appearance Button or a ComboBox placed on the form binds to the InputFormat of the editor and follows the formatting without InputPositionChanged handlers, as shown in Data Binding and Database Storage.

Keyboard Shortcuts in Menus

The editor handles Ctrl+C, Ctrl+X, Ctrl+V, Ctrl+Z and Ctrl+Y itself, as listed in Keyboard Shortcuts. To show these keys in the Edit menu without assigning them a second time, set the ShortcutKeyDisplayString of the menu items, for example to Ctrl+C, and leave their ShortcutKeys empty.

Keys the editor doesn't use, such as Ctrl+S for saving or Ctrl+F for the Find dialog box, go into the ShortcutKeys property of their menu items. The form then handles them for the whole window, whichever control has the focus. For a key that should work only while the editor has the focus, handle the KeyDown event of the TextControl instead, as the Keyboard Shortcuts page shows.

Next Steps