Mi è capitato ultimamente di avere dei problemi con il refresh di uno usercontrol da me realizzato, contenente alcuni poligoni riempiti con un gradiente lineare (una sfumatura): in pratica tutto va bene finchè non viene
effettuato lo scroll del mio componente, a questo punto alcune delle aree sfumate non vengono più ridisegnate
correttamente.
Il problema sembrerebbe dipendere dalla versione del framework (la 1.1.4322), poichè creando lo stesso
componente con Visual Studio 2005 Beta 1 ed il framework 2.0.40607, il ridisegno dopo lo scroll avviene
perfettamente in ogni circostanza.
A questo punto l'unica alternativa per ottenere il risultato richiesto con l'attuale versione del framework, è
quella di ricorrere alla gestione manuale dei messaggi che richiedono il ridisegno del componente; per fare
questo ci affidiamo al metodo WndProc dello usercontrol, in modo da intercettare i messaggi necessari.
Quindi procedendo con ordine, definiamo nella classe che rappresenta il nostro controllo la costante che
identifica il messaggio WM_PAINT
[C#]
private const int WM_PAINT = 0xF;
e poi implemento il metodo WndProc, che in pratica scarta tutti i messaggi ad eccezione di WM_PAINT, al
verificarsi del quale chiama un metodo che si occupa del disegno vero e proprio
[C#]
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
switch (m.Msg)
{
case WM_PAINT:
myPaint();
break;
}
}
Prima di eseguire il mio metodo, eseguo una chiamata al metodo WndProc base, passandogli naturalmente il
messaggio, per fare si che venga disegnato tutto ciò che è 'standard' nel controllo, dato che il mio metodo
si occupa solo delle 'sue cose' (a meno che non vogliate fare tutto voi).
Il metodo che si occupa del disegno è molto semplice, ed è molto simile a quello che scriverei nell'evento Paint
dello usercontrol; l'unica operazione aggiuntiva che si rende necessaria è il recupero dell'oggetto Graphics del
controllo (che nell'evento Paint è fornito da PaintEventArgs!)
[C#]
private void myPaint()
{
Graphics g = Graphics.FromHwnd(this.Handle);
// definisco gli estremi del poligono da disegnare (nell'esempio un rettangolo 50x100)
Point[] points = {new Point(0,0),new Point(100,0),new Point(100,50),new Point(50,0),new Point(0,0)};
// definisco il gradiente da utilizzare
Brush brush = new LinearGradientBrush(new Rectangle(0,0,5,50),Color.SteelBlue,Color.White,LinearGradientMode.Vertical);
// riempio il mio poligono
g.FillPolygon(brush,points,FillMode.Alternate);
g.Dispose();
}
Per fare ciò utilizzo il metodo statico FromHwnd della classe Graphics che a partire dall'Handle del controllo mi
restituisce proprio un oggetto Graphics. A questo punto il gioco è fatto, posso disegnare ciò che voglio, sicuro
che verrà ridisegnato sempre bene, a prova di scroll.