RichTextBox в C#: разбор и примеры
RichTextBox - элемент Windows Forms для ввода и показа форматированного текста: шрифты, цвета, выравнивание, списки и картинки в формате RTF. Он нужен там, где обычного TextBox мало: в простых редакторах, консолях логов, окнах справки. Ниже свойства, форматирование, загрузка и сохранение файлов, поиск с подсветкой и частые проблемы.

Содержание
Чем RichTextBox отличается от TextBox
В обычном TextBox весь текст оформлен одним шрифтом и одним цветом. RichTextBox позволяет задавать оформление отдельным фрагментам, вставлять изображения, хранить документ в RTF и открывать файлы из WordPad или Word в простом виде. Платой за это становится больший расход ресурсов и более сложный API.
| Возможность | TextBox | RichTextBox |
|---|---|---|
| Разные шрифты и цвета в тексте | Нет | Да |
| Формат RTF | Нет | Да, свойство Rtf |
| Маркированные списки, отступы | Нет | Да |
| Вставка изображений | Нет | Через буфер обмена и RTF |
| Автоматические ссылки | Нет | Свойство DetectUrls |
| Скорость на больших объёмах | Выше | Ниже |
Добавление на форму
Элемент можно перетащить из панели элементов в конструкторе Visual Studio или создать программно. Во втором случае важно не забыть добавить его в коллекцию Controls формы, иначе на экране ничего не появится.
var rtb = new RichTextBox
{
Location = new Point(10, 10),
Size = new Size(500, 300),
Font = new Font("Segoe UI", 11),
ScrollBars = RichTextBoxScrollBars.Vertical,
WordWrap = true,
Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right
};
Controls.Add(rtb);
Свойство Anchor с четырьмя значениями заставит поле растягиваться вместе с окном. Для окна с одним редактором проще задать Dock = DockStyle.Fill. Другие элементы управления на форме описаны в разделе блога про компоненты Windows Forms.
Основные свойства
| Свойство | Назначение |
|---|---|
Text | Простой текст без оформления |
Rtf | Содержимое вместе с форматированием в виде RTF-строки |
SelectedText, SelectionStart, SelectionLength | Выделенный фрагмент и его позиция |
SelectionFont, SelectionColor, SelectionBackColor | Оформление выделенного текста |
SelectionAlignment | Выравнивание абзаца: слева, по центру, справа |
SelectionBullet, SelectionIndent | Маркер списка и отступ |
ReadOnly | Запрещает редактирование |
WordWrap | Перенос по словам |
DetectUrls | Подсвечивать ссылки |
ZoomFactor | Масштаб от 0.015625 до 64 |
CanUndo, CanRedo | Доступность отмены и повтора |
Форматирование выделенного текста
Оформление применяют к текущему выделению. Сначала выделяют диапазон методом Select, затем задают свойства, начинающиеся на Selection.
rtb.Text = "Заголовок документа\nОбычный абзац с важным словом.";
rtb.Select(0, 19);
rtb.SelectionFont = new Font("Segoe UI", 16, FontStyle.Bold);
rtb.SelectionColor = Color.DarkBlue;
rtb.SelectionAlignment = HorizontalAlignment.Center;
int pos = rtb.Text.IndexOf("важным", StringComparison.Ordinal);
rtb.Select(pos, "важным".Length);
rtb.SelectionBackColor = Color.Yellow;
rtb.Select(rtb.TextLength, 0); // снять выделение, курсор в конец
Переключение жирного и курсива
Типичная задача редактора - кнопка "Ж", которая включает или выключает жирность для выделения. Ошибка в том, что SelectionFont равно null, когда в выделении смешаны разные шрифты. Эту ситуацию нужно обработать.
private void ToggleStyle(RichTextBox box, FontStyle style)
{
var current = box.SelectionFont ?? box.Font;
var newStyle = current.Style ^ style; // XOR переключает бит стиля
box.SelectionFont = new Font(current, newStyle);
}
// на кнопках
private void btnBold_Click(object sender, EventArgs e) => ToggleStyle(rtb, FontStyle.Bold);
private void btnItalic_Click(object sender, EventArgs e) => ToggleStyle(rtb, FontStyle.Italic);
Так как объект Font хранит ресурсы GDI, при частом создании шрифтов нужен контроль утечек. В примере предыдущий шрифт принадлежит элементу, поэтому его не освобождают вручную.
Добавление цветного текста в конец
Для логов и консолей важно дописывать строки с разным цветом. Метод AppendText сам по себе цвет не меняет, поэтому перед вставкой выделяют конец документа и задают SelectionColor.
public static void AppendColored(RichTextBox box, string text, Color color)
{
box.SelectionStart = box.TextLength;
box.SelectionLength = 0;
box.SelectionColor = color;
box.AppendText(text);
box.SelectionColor = box.ForeColor; // вернуть цвет по умолчанию
box.ScrollToCaret();
}
AppendColored(rtb, "Ошибка: файл не найден\n", Color.Firebrick);
AppendColored(rtb, "Готово\n", Color.ForestGreen);
Если логов очень много, элемент начнёт тормозить. Ограничьте размер, удаляя старые строки, или выводите сообщения пакетами раз в несколько десятков миллисекунд, а не по одной.
Загрузка и сохранение файлов
RichTextBox умеет читать и писать файлы без ручной работы со строками. Метод LoadFile открывает RTF или обычный текст, SaveFile записывает документ в нужном формате, который задаётся значением RichTextBoxStreamType.
private void OpenFile()
{
using var dlg = new OpenFileDialog
{
Filter = "RTF (*.rtf)|*.rtf|Текст (*.txt)|*.txt"
};
if (dlg.ShowDialog() != DialogResult.OK) return;
var type = Path.GetExtension(dlg.FileName).Equals(".rtf", StringComparison.OrdinalIgnoreCase)
? RichTextBoxStreamType.RichText
: RichTextBoxStreamType.PlainText;
rtb.LoadFile(dlg.FileName, type);
}
private void SaveFile()
{
using var dlg = new SaveFileDialog { Filter = "RTF (*.rtf)|*.rtf|Текст (*.txt)|*.txt" };
if (dlg.ShowDialog() != DialogResult.OK) return;
var type = dlg.FilterIndex == 1
? RichTextBoxStreamType.RichText
: RichTextBoxStreamType.UnicodePlainText;
rtb.SaveFile(dlg.FileName, type);
}
Для русского текста в обычном txt используйте UnicodePlainText, иначе кодировка может не совпасть с ожидаемой. Работу с файлами глубже описывает раздел блога про ввод-вывод.
Поиск и подсветка текста
Метод Find ищет подстроку и сразу выделяет её. Он принимает параметры поиска, например игнорирование регистра или поиск целого слова. Ниже подсветка всех совпадений.
public static int HighlightAll(RichTextBox box, string word, Color color)
{
if (string.IsNullOrEmpty(word)) return 0;
int count = 0, start = 0;
while (start < box.TextLength)
{
int index = box.Find(word, start, RichTextBoxFinds.None);
if (index < 0) break;
box.SelectionBackColor = color;
start = index + word.Length;
count++;
}
box.Select(0, 0);
return count;
}
Чтобы искать без учёта регистра, учтите: флаг RichTextBoxFinds.MatchCase включает регистр, а по умолчанию поиск нечувствителен к нему. Перед новой подсветкой снимите старую, выделив весь текст и вернув SelectionBackColor в цвет фона.
Работа с RTF
Свойство Rtf возвращает документ как строку с управляющими кодами и позволяет перенести форматированный текст из одного поля в другое, сохранить в базе данных или подготовить письмо. Встречается также запись простого RTF вручную.
string rtfText = rtb.Rtf; // полное содержимое с оформлением
other.Rtf = rtfText; // копия форматирования в другом поле
// минимальный документ из строки (латиница, без кодирования) (латиница, без кодирования)
rtb.Rtf = @"{\rtf1\ansi{\fonttbl{\f0 Arial;}}\f0\fs24 Plain \b bold\b0 and \i italic\i0 .}";
Кириллицу в ручной записи RTF нужно кодировать управляющими последовательностями вида \'e0 или в Unicode через \uN?. Поэтому для русского текста гораздо проще собирать оформление через свойства Selection, а не писать RTF руками.
События
Для отслеживания действий пользователя подходят несколько событий.
TextChangedсрабатывает при любом изменении текста, удобно для пометки "документ изменён".SelectionChangedпозволяет обновлять панель инструментов: состояние кнопок жирного, размер шрифта, выравнивание.LinkClickedвызывается при клике по ссылке при включённомDetectUrls.KeyDownнужен для горячих клавиш и перехвата Enter.
rtb.DetectUrls = true;
rtb.LinkClicked += (s, e) =>
{
// для открытия в браузере нужен UseShellExecute
System.Diagnostics.Process.Start(
new System.Diagnostics.ProcessStartInfo(e.LinkText!) { UseShellExecute = true });
};
rtb.SelectionChanged += (s, e) =>
{
statusLabel.Text = $"Позиция: {rtb.SelectionStart}, выделено: {rtb.SelectionLength}";
};
Открывать ссылку из пользовательского текста стоит осторожно: проверяйте, что адрес начинается с http:// или https://, иначе пользователь может запустить произвольную программу.
Вставка только простого текста
По умолчанию вставка из буфера обмена сохраняет форматирование источника, из-за чего в документ попадают чужие шрифты и цвета. Чтобы вставлять чистый текст, перехватывают нажатие Ctrl+V.
rtb.KeyDown += (s, e) =>
{
if (e.Control && e.KeyCode == Keys.V && Clipboard.ContainsText())
{
rtb.SelectedText = Clipboard.GetText();
e.Handled = true;
e.SuppressKeyPress = true;
}
};
Типичные проблемы
- Строка с оформлением сбрасывается: присвоение
Textстирает всё форматирование, а при добавлении текста через+=теряются стили. ИспользуйтеAppendText. - Мерцание при массовом изменении: оформляйте текст пакетом и не вызывайте
Selectтысячи раз подряд. - Исключение при
LoadFile: файл не RTF, а тип указан как RichText. Проверяйте расширение. - Выход за пределы диапазона в
Select: проверяйте, что начало и длина не превышаютTextLength. - Кнопки жирного не работают: забыли обработать
SelectionFont == nullпри смешанном выделении. - Нужен вывод логов из другого потока: обращайтесь к элементу через
Invoke, иначе получите исключение о доступе из другого потока.
Альтернативы
RichTextBox подходит для небольших редакторов и журналов. Если нужен полноценный редактор кода с нумерацией строк и подсветкой синтаксиса, берут сторонние компоненты вроде ScintillaNET или FastColoredTextBox. В WPF есть собственный элемент RichTextBox на основе FlowDocument, он гибче, но устроен иначе. Для вывода только для чтения с гиперссылками иногда достаточно WebView2 с HTML.
Частые вопросы
Как изменить цвет части текста в RichTextBox?
Выделите нужный фрагмент методом Select(start, length) и задайте SelectionColor. Для фона используйте SelectionBackColor.
Как добавить текст в конец без потери форматирования?
Вызовите AppendText. Присвоение через Text = Text + ... пересоздаёт содержимое и стирает оформление.
Как сохранить содержимое RichTextBox в файл?
Метод SaveFile(путь, RichTextBoxStreamType.RichText) сохранит с форматированием, а UnicodePlainText запишет обычный текст в Unicode.
Как прокрутить RichTextBox в конец?
Установите курсор в конец через SelectionStart = TextLength и вызовите ScrollToCaret(). Это нужно в окнах журнала.
Как запретить редактирование текста?
Присвойте ReadOnly = true. Выделение и копирование при этом остаются доступными, а цвет фона можно задать явно, чтобы поле не выглядело отключённым.
Можно ли вставить картинку в RichTextBox?
Напрямую свойством нет. Обычно картинку помещают в буфер обмена через Clipboard.SetImage и вставляют методом Paste, либо добавляют изображение в RTF-разметку.





