在 Windows 窗体中,DoubleBuffered 属性不会影响子控件,例如文本框。相反,它只影响为其设置的表单或面板。
如果要对表单上的子元素进行双缓冲,则需要实现手动双缓冲。
Bob Powell 写了一篇关于如何做到这一点的好文章(和其他文章)。
此外,从论坛回答鲍勃还说:
窗口的所有权意味着它们会不受控制地闪烁,因为您不能在目标窗口区域之外进行双重缓冲。例如,不能使具有子控件的面板对自身进行双重缓冲,并且
它是子控件。
正确执行此操作的唯一方法是创建一个使用保留模式图形系统形式进行所有绘图的单个控件。
因此,要使用手动双缓冲来调整无闪烁文本框的大小,您需要以某种方式将文本框渲染到后台缓冲区,然后将其显示为缓冲更新的一部分。如果可能的话:我不认为这会很容易。
[更新]
其他一些答案说这是专门针对 Windows 窗体的问题。这是不正确的,它实际上比这更深,是由 Windows GDI 引起的。例如,打开记事本/写字板等并粘贴一大块文本,调整窗口大小,并注意到同样的闪烁问题。
这是我多年前用来做类似事情的基本解决方案。它是一个简单的表单,包含一个多行文本框和一个继承自 Panel 的自定义类。两个控件具有相同的位置和大小。它使用 Forms ResizeBegin 和 ResizeEnd 在调整大小时显示面板,否则显示文本框。它并不完美,但它确实消除了闪烁。
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Bitmap bm = null;
private void textBox1_Resize(object sender, EventArgs e)
{
Graphics g = textBox1.CreateGraphics();
if (g.VisibleClipBounds.IsEmpty == false)
{
bm = new Bitmap((int)g.VisibleClipBounds.Width, (int)g.VisibleClipBounds.Height);
textBox1.DrawToBitmap(bm, new Rectangle(0, 0, (int)g.VisibleClipBounds.Width, (int)g.VisibleClipBounds.Height));
}
g.Dispose();
}
private void panelDB1_Paint(object sender, PaintEventArgs e)
{
if (bm != null)
{
e.Graphics.DrawImageUnscaled(bm, 0, 0,bm.Width,bm.Height );
}
}
private void Form1_ResizeBegin(object sender, EventArgs e)
{
panelDB1.BringToFront();
}
private void Form1_ResizeEnd(object sender, EventArgs e)
{
panelDB1.SendToBack();
}
}
class PanelDB : Panel
{
public PanelDB()
{
this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer,true);
//this.DoubleBuffered = true;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
}
}