TOC

This article is currently in the process of being translated into Russian (~99% done).

Элементы управления текстом:

The RichTextBox control

До сих пор мы рассматривали доступ к FlowDocument только в режиме "для чтения", однако в WPF есть контрол, который позволяет редактировать FlowDocument. Этот контрол называется RichTextBox.

Вы можете добавить RichTextBox без контента, прямо в окно. В этом случае будет создан экземпляр FlowDocument, который вы и будете редактировать. С другой стороны, вы можете обернуть FlowDocument в RichTextBox и таким образом задать начальный контент. Это делается подобным образом:

<Window x:Class="WpfTutorialSamples.Rich_text_controls.RichTextBoxSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="RichTextBoxSample" Height="200" Width="300">
    <Grid>
        <RichTextBox Margin="10">
            <FlowDocument>
                <Paragraph FontSize="36">Hello, world!</Paragraph>
                <Paragraph FontStyle="Italic" TextAlignment="Left" FontSize="14" Foreground="Gray">Thanks to the RichTextBox control, this FlowDocument is completely editable!</Paragraph>
            </FlowDocument>
        </RichTextBox>
    </Grid>
</Window>

Имея этот пример, вы можете сразу же начать редактировать контент вашего RichTextBox. Теперь контент доступен не только для чтения. Однако интересно то, как вы можете управлять текстом и работать с выделением. Мы рассмотрим это прямо сейчас.

Еще одна интересная сторона - это, конечно же, работа с различными возможностями форматирования. Мы рассмотрим это в следующей главе, где мы создадим небольшой, но полностью функциональный редактор текста.

Работа с текстом и выделением

Из-за того, что RichTextBox внутренне использует FlowDocument, а также по причине более высокой сложности RTF (Rich Text Format) по сравнению с обычным тестом, работа с текстом и выделением не настолько проста, как аналогичная в WPF TextBox.

В следующем примере демонстрируется ряд функций, которые работают с текстом и/или выделением в контроле RichTextBox:

<Window x:Class="WpfTutorialSamples.Rich_text_controls.RichTextBoxTextSelectionSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="RichTextBoxTextSelectionSample" Height="300" Width="400">
    <DockPanel>
        <WrapPanel DockPanel.Dock="Top">
            <Button Name="btnGetText" Click="btnGetText_Click">Get text</Button>
            <Button Name="btnSetText" Click="btnSetText_Click">Set text</Button>
            <Button Name="btnGetSelectedText" Click="btnGetSelectedText_Click">Get sel. text</Button>
            <Button Name="btnSetSelectedText" Click="btnSetSelectedText_Click">Replace sel. text</Button>
        </WrapPanel>
        <TextBox DockPanel.Dock="Bottom" Name="txtStatus" />
        <RichTextBox Name="rtbEditor" SelectionChanged="rtbEditor_SelectionChanged">
            <FlowDocument>
                <Paragraph FontSize="36">Hello, world!</Paragraph>
                <Paragraph FontStyle="Italic" TextAlignment="Left" FontSize="14" Foreground="Gray">Thanks to the RichTextBox control, this FlowDocument is completely editable!</Paragraph>
            </FlowDocument>
        </RichTextBox>
    </DockPanel>
</Window>
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;

namespace WpfTutorialSamples.Rich_text_controls
{
	public partial class RichTextBoxTextSelectionSample : Window
	{
		public RichTextBoxTextSelectionSample()
		{
			InitializeComponent();
		}

		private void btnGetText_Click(object sender, RoutedEventArgs e)
		{
			TextRange textRange = new TextRange(rtbEditor.Document.ContentStart, rtbEditor.Document.ContentEnd);
			MessageBox.Show(textRange.Text);
		}

		private void btnSetText_Click(object sender, RoutedEventArgs e)
		{
			TextRange textRange = new TextRange(rtbEditor.Document.ContentStart, rtbEditor.Document.ContentEnd);
			textRange.Text = "Another world, another text!";
		}

		private void btnGetSelectedText_Click(object sender, RoutedEventArgs e)
		{
			MessageBox.Show(rtbEditor.Selection.Text);
		}

		private void btnSetSelectedText_Click(object sender, RoutedEventArgs e)
		{
			rtbEditor.Selection.Text = "[Replaced text]";
		}

		private void rtbEditor_SelectionChanged(object sender, RoutedEventArgs e)
		{
			TextRange tempRange = new TextRange(rtbEditor.Document.ContentStart, rtbEditor.Selection.Start);
			txtStatus.Text = "Selection starts at character #" + tempRange.Text.Length + Environment.NewLine;
			txtStatus.Text += "Selection is " + rtbEditor.Selection.Text.Length + " character(s) long" + Environment.NewLine;
			txtStatus.Text += "Selected text: '" + rtbEditor.Selection.Text + "'";
		}
	}
}

Как вы можете видеть, разметка состоит из панели кнопок, одного RichTextBox и одного TextBox снизу, для показа состояния текущего выделения. Каждая из четырех доступных кнопок будет работать с RichTextBox, получая или устанавливая/заменяя текст, чтобы показать вам, как это делается.

В обработчиках интерфейса мы обрабатываем четыре события нажатия кнопок, а также событие SelectionChanged для RichTextBox, которое позволяет нам показывать статистику о текущем выделении.

Обратите особое внимание: вместо прямого доступа к свойству text у RichTextBox, как мы бы сделали с обычным TextBox, мы используем объекты TextRange с TextPointer'ами из RichTextBox, чтобы получить текст или выделение. Простыми словами, вот так это работает с RichTextBox, который, как уже упоминалось, не во всех случаях работает так же, как обычный TextBox.

Отступы между абзацами

Еще одна вещь, которую вы могли заметить во время работы с RichTextBox: когда вы нажимаете Enter, чтобы начать новый абзац, этот абзац вставляет пустую строку между старым и новым абзацом. Позвольте мне продемонстрировать это на скриншоте, где я ввел три строки текста, причем каждую отделил одним нажатием Enter:

Это нормальное поведение для работающего с абзацами текстового редактора, но в зависимости от того, где и как вы используете ваш RichTextBox, ваши пользователи могут быть сбиты с толку из-за того, что использование одного Enter приводит к большому промежутку между строками.

К счастью, это легко исправить. Дополнительное пустое пространство появляется из-за того, что по умолчанию абзацы имеют margin(отступ) больше чем 0. Поэтому исправить это легко, надо просто изменить это свойство, что мы можем сделать с использованием стиля, вот так:

<Window x:Class="WpfTutorialSamples.Rich_text_controls.RichTextBoxParagraphSpacingSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="RichTextBoxParagraphSpacingSample" Height="150" Width="300">
    <Grid>
        <RichTextBox Margin="10">
            <RichTextBox.Resources>
                <Style TargetType="{x:Type Paragraph}">
                    <Setter Property="Margin" Value="0" />
                </Style>
            </RichTextBox.Resources>
        </RichTextBox>
    </Grid>
</Window>

Сейчас между строками нет лишнего пустого места, и если вы хотите, вы можете расположить этот стиль в window или даже в App.xaml, если вы хотите использовать этот стиль не только для одного RichTextBox.

Итог

RichTextBox прост в использовании, имеет много особенностей прямо "из коробки", а еще вы его можете использовать для создания полнофункционального редактора текста. В следующей главе мы рассмотрим, как это делается. Это также поможет нам затронуть важные темы, такие как загрузка и сохранение текста из RichTextBox и как влиять на форматирование текста в этом контроле.


This article has been fully translated into the following languages: Is your preferred language not on the list? Click here to help us translate this article into your language!