2010-07-19 16 views
12

Tworzę funkcję, która pobiera RichTextBox i ma dostęp do listy słów kluczowych & "badwords". Muszę podkreślić wszystkie słowa kluczowe, które można znaleźć w RichTextBox , gdy użytkownik wpisuje, co oznacza, że ​​funkcja jest wywoływana za każdym razem, gdy zostanie wydany klucz edycji.Wyróżnianie składni RichTextBox w czasie rzeczywistym - Wyłączanie odświeżania

Napisałem tę funkcję, ale słowa i kursor w polu migoczą za dużo dla wygody.

Znalazłem rozwiązanie - aby wyłączyć możliwość odświeżenia RichTextBox podczas edycji i formatowania jego tekstu. Jednak jedynym sposobem, wiem, aby to zrobić, aby przesłonić funkcja „WndProc” i przechwytujący (co ja o to, aby zebrać) komunikat przemalować następująco:

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); 
} 

Jeżeli wartość logiczna „farba” jest ustawione na false tuż przed rozpoczęciem podświetlania i na true, kiedy skończę. Ale jak już powiedziałem, funkcja, którą wykonuję, musi przyjmować RichTextBox; Nie mogę użyć podklasy.

Czy istnieje sposób, aby wyłączyć automatyczne odświeżanie RichTextBox "z zewnątrz?"

Odpowiedz

21

Jest to niedopatrzenie w klasie RichTextBox. Inne elementy sterujące, takie jak ListBox, obsługują metody BeginUpdate i EndUpdate w celu powstrzymania malowania. Te metody generują komunikat WM_SETREDRAW. RTB faktycznie wspiera tę wiadomość, ale zapomniały dodać metody.

Po prostu dodaj je sam. Projekt + Dodaj klasę, wklej kod pokazany poniżej. Skomponuj i upuść kontrolkę z góry przybornika na formularz.

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; 
} 

Lub P/Invoke SendMessage bezpośrednio przed/po aktualizacji tekstu.

+1

Ten dodatek do zajęć nie działa dla mnie. Powoduje to pewne problemy z grafiką i ostatecznie sterowanie przestaje działać całkowicie, tak że nie można nawet przewijać kursora. FYI. – MoonKnight

+4

Bardzo standardowy tryb niepowodzenia podczas aktualizowania kontroli z wątku roboczego. –

+0

Hans, jestem zupełnie nowy w tych rzeczach. Co mówisz/sugerujesz powyższym? Że po powyższym rozszerzeniu klasy, aktualizacje do pola tekstowego powinny być wykonywane w osobnym wątku? Dziękuję za Twój czas. – MoonKnight

0

Najlepszym sposobem na osiągnięcie tego, co próbujesz zrobić, jest utworzenie aplikacji wielowątkowej. Będziesz chciał utworzyć jeden wątek, który sprawdzi tekst na twojej liście. Wątek ten umieści wszystkie znalezione instancje w kolejce. Będziesz także chciał stworzyć kolejny wątek, który będzie faktycznie podkreślał słowa. Ponieważ aby zaktualizować interfejs użytkownika, musisz użyć funkcji BeginInvoke() i Invoke(), będziesz musiał sprawdzić szybkość, z jaką zostanie wywołana. Tak więc nie więcej niż 20 razy na sekundę. Aby to zrobić, można użyć kodu:

DateTime lastInvoke=DateTime.Now; 

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

Ten wątek będzie sprawdzić swoją kolejkę do słów, które muszą być podświetlone lub ponownie podświetlony i będzie stale Sprawdź kolejkę dla wszelkich nowych aktualizacjach. Mam nadzieję, że to ma sens!

+0

Dzięki, że mogę spróbować, jeśli nie mogę znaleźć odpowiedzi na moje pytanie. To, co teraz robię, działa doskonale, jeśli mogę wyłączyć odświeżanie, gdy podkreślam. – Robz

+0

Tak, wiem, że nie jest to bezpośrednia odpowiedź na twoje pytanie, ale sądzisz, że docenisz dane wejściowe :) Ta metoda określa działanie programów takich jak Microsoft Word. – Icemanind

5

Nie zgromadziłem wystarczającej ilości punktów, by zmienić rekomendację Hansa. Więc dodałem tę odpowiedź, aby wspomnieć, że może być konieczne zażądanie odświeżenia przez wywołanie InvalidateRect. Niektóre implementacje aktualizacji Begin/End wykonują to automatycznie po ostatecznym wydaniu blokady aktualizacji. Podobnie w .Net, Control. Invalidate() można wywołać, która wywołuje natywną funkcję InvalidateRect.

MSDN: Wreszcie aplikacja może wywołać funkcję InvalidateRect w celu odświeżenia okna listy.

Zobacz WM_SETREDRAW

+0

Miałem takie same problemy, które opisywał Killercam - dodanie Invalidate() po ponownym włączeniu rysunku naprawiło to. – Oli

Powiązane problemy