Подсветка синтаксиса RichTextBox в режиме реального времени--отключение перерисовки
Я создаю функцию, которая принимает RichTextBox и имеет доступ к списку ключевых слов и "плохих слов". Мне нужно выделить любые ключевые слова и плохие слова, которые я нахожу в RichTextBox пока пользователь набирает, что означает, что функция вызывается каждый раз, когда освобождается клавиша редактирования.
Я написал эту функцию, но слова и курсор в поле мерцают слишком много для комфорта.
Я нашел решение-отключить способность RichTextBox к перекрасьте себя, пока я редактирую и форматирую его текст. Тем не менее, единственный способ, который я знаю, это переопределить функцию "WndProc" и перехватить (то, что я собирался собрать), перекрасить сообщение следующим образом:
protected override void WndProc(ref System.Windows.Forms.Message m)
{
if (m.Msg == 0x00f) {
if (paint)
base.WndProc(ref m);
else
m.Result = IntPtr.Zero;
}
else
base.WndProc(ref m);
}
где логическое "paint" имеет значение false непосредственно перед началом выделения и true, когда я заканчиваю. Но, как я уже сказал, функция, которую я делаю, должна принимать RichTextBox; я не могу использовать подкласс.
Итак, есть ли способ отключить автоматический перекраска RichTextBox " извне?'
3 ответов
это оплошность в классе RichTextBox. Другие элементы управления, такие как ListBox, поддерживают методы BeginUpdate и EndUpdate для подавления рисования. Эти методы генерируют сообщение WM_SETREDRAW. RTB фактически поддерживает это сообщение, но они забыли добавить методы.
просто добавьте их сами. Project + Add Class, вставьте код, показанный ниже. Скомпилируйте и поместите элемент управления из верхней части панели инструментов в форму.
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
class MyRichTextBox : RichTextBox {
public void BeginUpdate() {
SendMessage(this.Handle, WM_SETREDRAW, (IntPtr)0, IntPtr.Zero);
}
public void EndUpdate() {
SendMessage(this.Handle, WM_SETREDRAW, (IntPtr)1, IntPtr.Zero);
this.Invalidate();
}
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
private const int WM_SETREDRAW = 0x0b;
}
Или P / Invoke SendMessage непосредственно перед/после обновления текста.
Я не накопил достаточно очков, чтобы изменить рекомендацию Ханса. Поэтому я добавил Это ответ упомянуть, что может потребоваться запросить перекраску, позвонив InvalidateRect. Некоторые реализации Begin/End Update делают это автоматически после окончательного выпуска блокировки обновления. Аналогично в .Net,управления.недействительным () можно вызвать, который вызывает native InvalidateRect
лучше всего выполнить то, что вы пытаетесь сделать, это создать многопоточное приложение. Вы захотите создать один поток, который проверяет текст по вашему списку. Этот поток помещает все найденные экземпляры в очередь. Вы также захотите создать другой поток, который делает фактическую подсветку слов. Поскольку вам нужно будет использовать BeginInvoke() и Invoke () для обновления пользовательского интерфейса, вы захотите убедиться, что вы задушите скорость, с которой это вызывается. Я бы так не больше 20 раза в секунду. Для этого вы должны использовать такой код:
DateTime lastInvoke=DateTime.Now;
if ((DateTime.Now - lastInvoke).TotalMilliseconds >=42)
{
lastInvoke=DateTime.Now;
...Do your highlighting here...
}
этот поток будет проверять вашу очередь на слова, которые должны быть выделены или повторно выделены, и будет постоянно проверять очередь на наличие новых обновлений. Надеюсь, это имеет смысл!