2010-07-19 4 views
12

Sto creando una funzione che accetta un RichTextBox e ha accesso a un elenco di parole chiave & "badwords". Devo evidenziare qualsiasi parola chiave & che trovo nel RichTextBox mentre l'utente sta digitando, il che significa che la funzione viene chiamata ogni volta che viene rilasciato un tasto di modifica.Evidenziazione sintassi RichTextBox in tempo reale - Disabilitazione del repaint

Ho scritto questa funzione, ma le parole e il cursore nel riquadro sfarfallio troppo per il comfort.

Ho scoperto una soluzione - per disabilitare la capacità del RichTextBox di ridisegnare se stesso mentre sto modificando e formattando il suo testo. Tuttavia, l'unico modo che conosco per farlo è quello di ignorare la funzione "WndProc" e intercetta (quello che ho su di raccogliere è) il messaggio di ridipingere come segue:

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

Qualora il booleano 'vernice' è impostato su false appena prima di iniziare l'evidenziazione e su true quando ho finito. Ma come ho detto, la funzione che faccio deve contenere un RichTextBox; Non posso usare una sottoclasse.

Quindi, c'è un modo per disabilitare la ridipinture automatica di un RichTextBox "dall'esterno?"

risposta

21

È una svista nella classe RichTextBox. Altri controlli, come ListBox, supportano i metodi BeginUpdate e EndUpdate per sopprimere la pittura. Questi metodi generano il messaggio WM_SETREDRAW. RTB supporta infatti questo messaggio, ma si è dimenticato di aggiungere i metodi.

Basta aggiungerli da soli. Progetto + Aggiungi classe, incolla il codice mostrato di seguito. Compilare e rilasciare il controllo dalla parte superiore della casella degli strumenti sul modulo.

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

Oppure P/Invoke SendMessage direttamente prima/dopo aver aggiornato il testo.

+1

Questa aggiunta alla classe non funziona per me. Causa alcuni problemi grafici e infine il controllo per smettere di funzionare completamente, in modo che non si possa nemmeno scorrere il cursore. FYI. – MoonKnight

+4

Modalità di errore standard piuttosto quando si aggiorna il controllo da un thread di lavoro. –

+0

Hans, sono relitivamente nuovo a questa roba. Cosa stai dicendo/sottintendendo quanto sopra? Che seguendo l'estensione di classe sopra, che gli aggiornamenti alla casella di testo dovrebbero essere eseguiti su un thread separato? Grazie per il tuo tempo. – MoonKnight

0

La soluzione migliore per realizzare ciò che si sta tentando di fare è creare un'applicazione multithread. Dovrai creare un thread che controlli il testo rispetto al tuo elenco. Questo thread inserirà tutte le istanze che trova in una coda. Dovrai anche creare un altro thread che evidenzi l'effettiva evidenziazione delle parole. Poiché è necessario utilizzare BeginInvoke() e Invoke() per aggiornare l'interfaccia utente, è necessario assicurarsi di limitare la velocità con cui viene chiamato. Farei così non più di 20 volte al secondo. Per fare questo, devi usare il codice come questo:

DateTime lastInvoke=DateTime.Now; 

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

Questo thread controllerà la coda per le parole che devono essere evidenziati o ri-evidenziato e controllerà costantemente la coda per eventuali nuovi aggiornamenti. Spero che questo abbia un senso!

+0

Grazie, potrei provare che, se non riesco a trovare una risposta alla mia domanda. Quello che sto facendo adesso funziona perfettamente se posso disabilitare il ridisegno mentre sto evidenziando. – Robz

+0

Sì, so che non è una risposta diretta alla tua domanda, ma ho pensato che apprezzerai l'input :) Questo metodo è il modo in cui i programmi, come Microsoft Word, funzionano. – Icemanind

5

Non ho accumulato abbastanza punti per modificare la raccomandazione di Hans. Quindi ho aggiunto questa risposta per ricordare che potrebbe essere necessario richiedere un aggiornamento chiamando lo InvalidateRect. Alcune implementazioni di aggiornamento Begin/End lo fanno automaticamente al rilascio finale del blocco di aggiornamento. Analogamente in .Net, Controllo. Invalidate() può essere chiamato che richiama la funzione nativa InvalidateRect.

MSDN: Infine, l'applicazione può chiamare la funzione InvalidateRect per fare in modo che la casella di riepilogo venga ridipinta.

Vedi WM_SETREDRAW

+0

Avevo gli stessi problemi che descriveva Killercam - aggiungendo un Invalidate() dopo aver riattivato il disegno. – Oli