我的程序在面板上绘制文本,但如果我想删除文本,我必须重新绘制。如何手动调用(触发)绘画事件?
this.Invalidate(); // request a delayed Repaint by the normal MessageLoop system
this.Update(); // forces Repaint of invalidated area
this.Refresh(); // Combines Invalidate() and Update()
通常情况下,您只需要调用Invalidate()
,然后让系统将其与其他屏幕更新合并。如果您很匆忙,可以调用Refresh()
,但这样做可能会由于其他控件(特别是父控件)无效而使其连续重绘多次。
Windows(Win32和WinForms.Net)处理此问题的常规方式是等待消息队列为空,然后处理所有失效的屏幕区域。这样做是有效的,因为当某些变化发生时,通常会导致其他内容(控件)也发生变化。
Update()最常见的场景是在for循环中更改属性(比如label1.Text,它会使Label失效),而该循环会暂时阻塞消息循环。每当使用它时,您都应该问自己是否应该使用线程。但答案并不总是肯定的。
this.Paint += this.OnPaint;
private void OnPaint(object sender, PaintEventArgs e)
{
this.DrawFrame(e.Graphics);
}
private void RedrawFrame()
{
var r = new Rectangle(
0, 0, this.Width, this.Height);
this.Invalidate(r);
this.Update();
}
private void RedrawFrame()
{
var g = Graphics.FromHwnd(this.Handle);
this.DrawFrame(g);
}
using() {}
中) - H H我认为你也可以调用Refresh()
方法。
也许这是一个老问题,这就是为什么这些答案对我没有用的原因...使用Visual Studio 2019,在进行一些调查后,我找到了以下解决方案:
this.InvokePaint(this, new PaintEventArgs(this.CreateGraphics(), this.DisplayRectangle));
根据上下文,刷新可能会使代码更易读。
使用 Control.InvokePaint
,您还可以将其用于手动双缓冲。
this.Invalidate()
需要最少的CPU资源,因为您没有强制执行标准消息循环之外的操作,如果您可以调用this.Invalidate(false)
,那么只在主控件/窗体上调用OnPaint()
而不是子控件,这一点尤其正确。对于我的一个用户控件,从this.Update()
到this.Invalidate(false)
的转换将CPU负载降低了4倍。 - Special Sauce