Update, Invalidate und Refresh
Eine Frage, die immer wieder auftaucht: Wo ist der Unterschied zwischen Invalidate, Update und Refresh?
MSDN sagt dazu...
- "Die Invalidate-Methode steuert, was gezeichnet oder neu gezeichnet wird. Die Update-Methode steuert, wann gezeichnet oder neu gezeichnet wird. Wenn Sie, statt Refresh aufzurufen, die Invalidate-Methode und die Update-Methode gemeinsam verwenden, hängt das, was neu gezeichnet wird, davon ab, welche Überladung von Invalidate Sie verwenden. Die Update-Methode erzwingt einfach, dass das Steuerelement unmittelbar gezeichnet wird, während die Invalidate-Methode steuert, was gezeichnet wird, wenn die Update-Methode von Ihnen aufgerufen wird." [1]
- Invalidate "erklärt die ganze Oberfläche des Steuerelements für ungültig und bewirkt, dass das Steuerelement neu gezeichnet wird." [2]
Das heißt...
Über Invalidate wird eine WM_PAINT-Nachricht (Paint-Ereignis) in die Nachrichtenwarteschlange gestellt. Diese Nachricht bewirkt ein Neuzeichnen der Grafikfläche. Da man jedoch nicht genau weiß, wann die Nachricht abgearbeitet wird, kann mit Hilfe der Update-Methode das sofortige Neuzeichnen erzwungen werden (unter Umgehung der Warteschlange). Refresh fasst die Methoden Invalidate(true) und Update() zusammen und sorgt somit für das sofortige Neuzeichnen des angegebenen Elements und seiner Kinder.
Die manuelle Verwendung der invalidate-Methode ist jedoch flexibler, da es über die zahlreichen Überladungen möglich ist, zu entscheiden, ob die Kindelemente auch neugezeichnet werden sollen (invalidate(true)) oder nicht (invalidate(false)). Weiterhin kann der neu zu zeichnende Bereich durch die Angabe eines Rechtecks eingegrenzt werden. Besonders die Eingrenzung der neu zu zeichnenden Fläche ist interessant und kann zu Performanceverbesserungen führen.
Zusammenfassend kann man sich die Funktionalität wie folgt merken:
- Invalidate markiert Flächen die aktualisiert werden sollen und sorgt für deren Neuzeichnung (meist die beste Variante)
- Update sorgt für das sofortige Aktualisieren der durch Invalidate angegebenen Flächen
- Refresh fasst Invalidate und Update zusammen, nimmt einem jedoch die Möglichkeit, den zu aktualisierenden Bereich einzugrenzen
Des Weiteren ist es noch wichtig, dass das Verdecken des Fensters ebenfalls zum Neuzeichnen führt, da das Paint-Ereignis systemseitig ausgelöst wird. Dabei wird jedoch nur der überdeckte/veränderte Bereich aktualisiert.
Beispielprogramm
Das folgende C#-Programm besteht aus einem Panel und einem Button. Bei jedem Aufruf der Paint-Methode wird die Hintergrundfarbe zufällig geändert. Per Buttonklick kann die Refresh-Methode aufgerufen werden. Das Ziehen eines Rechteckes mit der Maus sorgt dafür, dass der entsprechende Bereich der Invalidate-Methode übergeben wird. In der Abbildung sieht man, dass ein Fenster im rechten Teil über die Anwendung gezogen wurde und dementsprechend die Paint-Methode schnell hintereinander aufgerufen wurde. Danach wurde ein Bereich mit der Maus für ungültig erklärt und dementsprechend neu gezeichnet (grünes Rechteck).
public partial class Form1 : Form
{
Random randomizer = new Random();
Point p1 = new Point();
Point p2 = new Point();
public Form1()
{
InitializeComponent();
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.Clear(Color.FromArgb(randomizer.Next(255), randomizer.Next(255), randomizer.Next(255)));
}
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
p1.X = e.X;
p1.Y = e.Y;
}
private void panel1_MouseUp(object sender, MouseEventArgs e)
{
p2.X = e.X;
p2.Y = e.Y;
panel1.Invalidate(new Rectangle(p1, new Size(p2.X - p1.X, p2.Y - p1.Y)));
}
private void button1_Click(object sender, EventArgs e)
{
panel1.Refresh();
}
}
Funktionsweise von Windows
Zum besseren Verständnis noch eine kurze Übersicht über die allgemeine Funktionsweise von Windows-Anwendungen. Für jedes Programm wird von Windows eine Nachrichtenwarteschlange (Message Queue) vorgehalten, die die Ereignisse - wie das Drücken einer Taste - aufnimmt. Diese Schlange wird durch das Programm abgefragt (Nachrichtenschleife in der WinMain-Methode) und Windows signalisiert (über DispatchMessage, aktuelles Fenster ermitteln), dass das Ereignis an das Programm übergeben werden soll (senden an WndProc des entsprechenden Fensters). Das Programm entscheidet nun, wie es auf das Ereignis reagiert. Wenn es das Ereignis nicht bearbeiten kann, wird es zurück an Windows geschickt (DefWindowProc), das daraufhin entscheidet was zu tun ist (oft ignorieren).
In C# ist dieser Mechanismus zunächst nicht ersichtlich (aber dennoch vorhanden). Wer jedoch schonmal ein C++ Programm erstellt hat, dem wird dieser Code schon über den Weg gelaufen sein. In C# hat man aber auch die Möglichkeit etwas tiefer ins System zu schauen, indem man einfach die Windows-DLLs einbindet. Alternativ ist es auch ganz ohne Mehraufwand möglich, bei Komponenten die WndProc-Methode aufzurufen:
Message m=new Message();
...
this.WndProc(ref m);
Was bedeutet das nun für die drei GDI-Methoden? Invalidate setzt eine WM_PAINT-Nachricht in die windowsseitige Nachrichtenwarteschlange. Es ist unbestimmt, wann das Ereignis vom Programm bearbeitet wird. Update hingegen sendet die WM_PAINT-Nachricht unter Umgehung der Warteschlange an sich selbst (per sendmessage()), also an die WndProc-Methode, was zur sofortigen Bearbeitung führt. Wenn auf die explizite Angabe von Invalidate/Update/Refresh verzichtet wird, wird eine Fläche erst dann neugezeichnet, wenn das System eine WM_PAINT-Nachricht erzeugt, wie z.B. beim Überdecken des Fensters.
Kommentare
Noch keine Kommentare.
