TX Text Control .NET for Windows Forms

Viewing, Zooming, and Navigation

Topic

Whether the editor shows pages like a printout or text that flows with the width of the form, how large it draws them and where the user is in a long document are settings of the TextControl. Users change them in the View tab of the ribbon and the status bar; your code sets them with a few properties, moves the input position to a page and reacts when the user zooms or turns a page.

The code runs in Form1.cs with a TextControl named textControl1, the editor of Create Your First Windows Forms Application.

Choose a View Mode

ViewMode decides how the document is laid out on the screen:

ValueThe editor shows
PageViewPages with gaps and a desktop background, formatted with the page size and margins; headers and footers are displayed
NormalText formatted with the page size and margins, without the page view; headers and footers can be inserted but aren't displayed
FloatingTextText as wide as the control, with a vertical scroll bar for unlimited text; the page size, margins, headers and footers are ignored
SimpleControlText formatted to the width and height of the control; when it is full, no more text can be entered

PageView is the view of a word processor and the only mode in which the editor counts pages. The following code sets it when the form opens:

private void Form1_Load(object sender, EventArgs e)
{
    // Show pages like a printed document
    textControl1.ViewMode = ViewMode.PageView;
}

In page view, BackgroundStyle chooses the background around the pages: ColorScheme uses the color scheme of the system or the colors of DisplayColors, and ClassicColors a dark gray. ScrollBars takes a value of the System.Windows.Forms.ScrollBars enumeration: None, Horizontal, Vertical or Both.

In SimpleControl mode, the control can also change its own width or height as the user types, like a text box that grows with its text. Let the Control Grow With Its Content shows the AutoControlSize settings and events for this.

Zoom the Document

Users zoom with the slider of the status bar, the zoom items of the View tab or Ctrl and the mouse wheel. In code, ZoomFactor sets and returns the zoom factor in percent, and Zoom zooms to a factor or to a value of ZoomOption:

private void zoomInButton_Click(object sender, EventArgs e)
{
    textControl1.Zoom(textControl1.ZoomFactor + 10);
}

private void pageWidthButton_Click(object sender, EventArgs e)
{
    // Fit the width of the page into the control
    textControl1.Zoom(ZoomOption.PageWidth);
}
  • ZoomOption.PageWidth fits the width of a page into the control, ZoomOption.WholePage the current page, and ZoomOption.TextWidth the text of a line.
  • In PageView and Normal mode, the factor can be from 10 up to ushort.MaxValue percent. In the other modes, it can be from 10 to 400 percent.
  • After the zoom factor has changed, the TextControl raises Zoomed. A handler can show the new factor:
private void textControl1_Zoomed(object sender, EventArgs e)
{
    zoomLabel.Text = $"{textControl1.ZoomFactor} %";
}

zoomLabel is a Label on the form. The blog article Zoom Tricks: Disabling CTRL + MOUSE WHEEL and More turns off zooming with the mouse wheel and adds keyboard shortcuts for zooming.

Show Formatting Marks and Markers

Some characters and objects are invisible in a printed document but help while editing:

PropertyShows
ControlCharsAll control characters, such as spaces, tabs and paragraph ends
PermanentControlCharsSelected control characters all the time, as a combination of PermanentControlChar values such as ParagraphEnd, ForcedPageBreak or SectionBreak
TextFrameMarkerLinesMarker lines around text frames without a border
DrawingMarkerLinesMarker lines around drawings
DocumentTargetMarkersMarkers at hypertext targets, such as bookmarks

Users don't need code for these settings: the View tab, a RibbonViewTab, switches between Print Layout and Draft in its Document Views group, sets the zoom factor or fits the page, its width or the text width into the control in its Zoom group, shows and hides the rulers and the status bar in its Toolbars group, and turns table gridlines, bookmark markers, marker lines, control characters and frame anchors on and off in its Show group.

The View tab of TX Text Control Words with the groups Document Views (Print Layout, Draft), Zoom (Zoom, 100 %, Full Page, Page Width, Text Width), Toolbars, Show and Application View.

In code, a combination of permanent control characters is written with the bitwise OR operator:

// Always show paragraph ends and page breaks
textControl1.PermanentControlChars = PermanentControlChar.ParagraphEnd | PermanentControlChar.ForcedPageBreak;

Go to a Page

The input position has a page, a line and a column. Setting InputPosition to a new InputPosition moves the caret there, and ScrollTo scrolls it into view:

private void goToPageButton_Click(object sender, EventArgs e)
{
    int page = 3;

    // Pages exist only in page view
    if (textControl1.ViewMode != ViewMode.PageView || page > textControl1.Pages)
    {
        return;
    }

    // Line 1, column 0 is the start of the page
    textControl1.InputPosition = new InputPosition(page, 1, 0);
    textControl1.InputPosition.ScrollTo(InputPosition.ScrollPosition.Top);
    textControl1.Focus();
}

Pages returns the number of pages of the document. Selections and Caret Position describes the InputPosition constructor and ScrollTo in detail.

GetPages returns a PageCollection with a Page object per page, and null outside page view. Page.Select selects the text of a page, without its header and footer. For users, the GotoDialog is a modeless dialog box that moves the input position to a page, section, line, table or bookmark:

private void goToDialogButton_Click(object sender, EventArgs e)
{
    GotoDialog dialog = new GotoDialog(textControl1);
    dialog.Show();
}

React to the Position in the Document

PageChanged occurs when the input position moves to another page. InputPosition.Page then returns the new page, in page view only:

private void textControl1_PageChanged(object sender, EventArgs e)
{
    pageLabel.Text = $"Page {textControl1.InputPosition.Page} of {textControl1.Pages}";
}

The StatusBar of TX Text Control shows the same information without code; see Rulers and Status Bar. HScroll and VScroll occur when the user scrolls, and ScrollLocation returns or sets the upper-left corner of the visible part of the document, in twips.

Scroll to a Text Position Without Moving the Caret

InputPosition.ScrollTo moves the caret first. To bring a text position into view and leave the caret where it is, set ScrollLocation to the position of the character:

private void ScrollToTextPosition(int textPosition)
{
    Point location;

    // TextChars counts from 1, text positions from 0
    if (textPosition + 1 <= textControl1.TextChars.Count)
    {
        location = new Point(0, textControl1.TextChars[textPosition + 1].Bounds.Y);
    }
    else
    {
        // Past the end: scroll to the last line
        location = new Point(0, textControl1.Lines[textControl1.Lines.Count].TextBounds.Y);
    }

    textControl1.ScrollLocation = location;
}

The code works as follows:

  • The text position is zero-based, as Selection.Start and InputPosition.TextPosition are. The indexer of TextChars counts characters from 1, so the character at a text position is TextChars[textPosition + 1].
  • TextChar.Bounds and Line.TextBounds are given in twips from the upper-left corner of the document, the same coordinates as ScrollLocation.
  • A position beyond the last character scrolls to the last line, which Lines[Lines.Count] returns from the one-based Lines collection.

Point is the System.Drawing.Point structure.

Show the Page Number of the Visible Page

In a read-only viewer, users scroll instead of moving the caret, so InputPosition.Page and PageChanged stay on the page where the caret is. The page the user looks at is the page of the line in the middle of the control. LineCollection.GetItem with a Point, in pixels from the upper-left corner of the control, returns the line displayed there, taking the scroll position into account. Update the display in the VScroll event:

private void textControl1_VScroll(object sender, EventArgs e)
{
    // The line in the middle of the visible part
    Line line = textControl1.Lines.GetItem(new Point(0, textControl1.Height / 2));
    if (line == null || textControl1.ViewMode != ViewMode.PageView)
    {
        return;
    }

    int section = textControl1.GetPages()[line.Page].Section;
    pageLabel.Text = $"Page {line.Page} of {textControl1.Pages}, section {section} of {textControl1.Sections.Count}";
}

Line.Page is the number of the page, counted from 1. GetPages()[number] returns that Page, and Page.Section the number of its section; when a page holds several sections, it is the first one, which sets the size and orientation of the page.

Next Steps