Подтвердить что ты не робот

Выделение синтаксиса 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);
}

Если для boolean 'paint' установлено значение false, перед тем, как я начну выделять и вернусь, когда закончите. Но, как я уже сказал, функция, которую я делаю, должна принимать RichTextBox; Я не могу использовать подкласс.

Итак, есть ли способ отключить автоматическую перерисовку RichTextBox 'извне?'

4b9b3361

Ответ 1

Это надзор в классе 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 непосредственно перед/после обновления текста.

Ответ 2

Я не накопил достаточного количества баллов, чтобы исправить рекомендацию Ганса. Поэтому я добавил этот Ответ, чтобы упомянуть, что может потребоваться запросить перерисовку, вызвав InvalidateRect. Некоторые реализации Begin/End Update делают это автоматически после окончательной версии блокировки обновления. Аналогично в .Net может быть вызван элемент управления. Invalidate(), который вызывает встроенную функцию InvalidateRect.

MSDN: Наконец, приложение может вызвать функцию InvalidateRect, чтобы вызвать перерисовку списка.

См. WM_SETREDRAW

Ответ 3

Лучше всего сделать то, что вы пытаетесь сделать, - создать многопоточное приложение. Вы хотите создать один поток, который проверяет текст по вашему списку. Этот поток будет помещать любые экземпляры, которые он находит в очередь. Вы также захотите создать еще один поток, который делает фактическое выделение слов. Поскольку вам нужно будет использовать BeginInvoke() и Invoke() для обновления пользовательского интерфейса, вам нужно убедиться, что вы дросселируете скорость, с которой это вызвано. Я бы так больше 20 раз в секунду. Для этого вы должны использовать следующий код:

DateTime lastInvoke=DateTime.Now;

if ((DateTime.Now - lastInvoke).TotalMilliseconds >=42)
{
    lastInvoke=DateTime.Now;
    ...Do your highlighting here...
}

Этот поток проверяет вашу очередь на слова, которые нужно выделить или переосмыслить, и будет постоянно проверять очередь на любые новые обновления. Надеюсь, это имеет смысл!