C# 在 WinForms 中的控件更新期间闪烁(例如 DataGridView)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/63974/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 10:22:38  来源:igfitidea点击:

Flickering during updates to Controls in WinForms (e.g. DataGridView)

提问by Grzenio

In my application I have a DataGridView control that displays data for the selected object. When I select a different object (in a combobox above), I need to update the grid. Unfortunately different objects have completely different data, even different columns, so I need to clear all the existing data and columns, create new columns and add all the rows. When this is done, the whole control flickers horribly and it takes ages. Is there a generic way to get the control in an update state so it doesn't repaint itself, and then repaint it after I finish all the updates?

在我的应用程序中,我有一个 DataGridView 控件,用于显示所选对象的数据。当我选择一个不同的对象(在上面的组合框中)时,我需要更新网格。不幸的是,不同的对象具有完全不同的数据,甚至不同的列,因此我需要清除所有现有数据和列,创建新列并添加所有行。完成此操作后,整个控件会可怕地闪烁,并且需要很长时间。有没有一种通用的方法可以让控件处于更新状态,这样它就不会重新绘制自己,然后在我完成所有更新后重新绘制它?

It is certainly possible with TreeViews:

TreeViews 当然可以:

myTreeView.BeginUpdate();
try
{
    //do the updates
}
finally
{
    myTreeView.EndUpdate();
}

Is there a generic way to do this with other controls, DataGridView in particular?

有没有一种通用的方法可以用其他控件(特别是 DataGridView)来做到这一点?

UPDATE: Sorry, I am not sure I was clear enough. I see the "flickering", because after single edit the control gets repainted on the screen, so you can see the scroll bar shrinking, etc.

更新:对不起,我不确定我是否足够清楚。我看到“闪烁”,因为在单次编辑后,控件会在屏幕上重新绘制,因此您可以看到滚动条缩小等。

采纳答案by Skizz

Rather than adding the rows of the data grid one at a time, use the DataGridView.Rows.AddRangemethod to add all the rows at once. That should only update the display once. There's also a DataGridView.Columns.AddRangeto do the same for the columns.

不是一次添加数据网格的行,而是使用该DataGridView.Rows.AddRange方法一次添加所有行。那应该只更新一次显示。还有一个DataGridView.Columns.AddRange对列做同样的事情。

回答by TheSmurf

Sounds like you want double-buffering:

听起来你想要双缓冲:

http://www.codeproject.com/KB/graphics/DoubleBuffering.aspx

http://www.codeproject.com/KB/graphics/DoubleBuffering.aspx

Although this is mainly used for individual controls, you can implement this in your Windows Forms control or Form.

尽管这主要用于单个控件,但您可以在 Windows 窗体控件或窗体中实现它。

回答by TK.

Unfortunatly, I think that thins might just be a by-product of the .net framework. I am experiencing similar flickering albeit with custom controls. Many of the reference material I have read indicates this, alongside the fact the the double buffering method failed to remove any flickering for me.

不幸的是,我认为 Thins 可能只是 .net 框架的副产品。尽管使用自定义控件,但我遇到了类似的闪烁。我读过的许多参考资料都表明了这一点,同时双缓冲方法未能为我消除任何闪烁。

回答by Skizz

Double buffering won't help here since that only double buffers paint operations, the flickering the OP is seeing is the result of multiple paint operations:

双缓冲在这里无济于事,因为只有双缓冲绘制操作,OP 看到的闪烁是多次绘制操作的结果:

  • Clear control contents -> repaint
  • Clear columns -> repaint
  • Populate new columns -> repaint
  • Add rows -> repaint
  • 清除控制内容 -> 重绘
  • 清除列 -> 重绘
  • 填充新列 -> 重绘
  • 添加行 -> 重绘

so that's four repaints to update the control, hence the flicker. Unfortunately, not all the standard controls have the BeginUpdate/EndUpdate which would remove all the repaint calls until the EndUpdate is called. Here's what you can do:

所以这是四次重绘来更新控件,因此闪烁。不幸的是,并非所有标准控件都具有 BeginUpdate/EndUpdate,这将删除所有重绘调用,直到调用 EndUpdate。您可以执行以下操作:

  1. Have a different control for each data set and Show/Hide the controls,
  2. Remove the control from its parent, update and then add the control again,
  3. Write your own control.
  1. 为每个数据集设置不同的控件并显示/隐藏控件,
  2. 从其父控件中删除控件,更新然后再次添加控件,
  3. 编写自己的控件。

Options 1 and 2 would still flicker a bit.

选项 1 和 2 仍然会闪烁一点。

On the .Net GUI program I'm working on, I created a set of custom controls that eliminated all flicker.

在我正在开发的 .Net GUI 程序中,我创建了一组消除所有闪烁的自定义控件。

回答by Ken Wootton

The .NET control supports the SuspendLayoutand ResumeLayoutmethods. Pick the appropriate parent control (i.e. the control that hosts the controls you want to populate) and do something like the following:

.NET 控件支持SuspendLayoutResumeLayout方法。选择适当的父控件(即承载要填充的控件的控件)并执行如下操作:

this.SuspendLayout();

// Do something interesting.

this.ResumeLayout();

回答by Brian Hasden

This worked for me.

这对我有用。

http://www.syncfusion.com/faq/windowsforms/search/558.aspx

http://www.syncfusion.com/faq/windowsforms/search/558.aspx

Basically it involves deriving from the desired control and setting the following styles.

基本上它涉及从所需的控件派生并设置以下样式。

SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true); 
SetStyle(ControlStyles.DoubleBuffer, true); 

回答by Jon

People seem to forget a simple fix for this:

人们似乎忘记了一个简单的解决方法:

Object.Visible = false;

//do update work

Object.Visible = true;

I know it seems weird, but that works. When the object is not visible, it won't redraw itself. You still, however, need to do the beginand endupdate.

我知道这看起来很奇怪,但确实有效。当对象不可见时,它不会重绘自身。但是,您仍然需要执行beginend更新。

回答by Ramgy Borja

You may also try this, its work.

你也可以试试这个,它的工作。

public static void DoubleBuffered(Control formControl, bool setting)
{
    Type conType = formControl.GetType();
    PropertyInfo pi = conType.GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic);
    pi.SetValue(formControl, setting, null);
}