Visual C# 表单更新导致闪烁

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/181374/
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 16:53:35  来源:igfitidea点击:

visual c# form update results in flickering

c#winforms

提问by

I have a .net app that I've written in c#. On some forms I frequent update the display fields. In some cases every field on the form (textboxes, labels, picturebox, etc) has its value changed. Plus the frequency of the changes could possibly be every second. However, currently there is a horrible flickering everytime the form is updated. How can I stop the flickering? Is there a way to maybe double buffer? Please help!

我有一个用 c# 编写的 .net 应用程序。在某些表单上,我经常更新显示字段。在某些情况下,表单上的每个字段(文本框、标签、图片框等)的值都已更改。加上变化的频率可能是每秒。但是,目前每次更新表单时都会出现可怕的闪烁。我怎样才能停止闪烁?有没有办法双缓冲?请帮忙!

回答by Matthew Scharley

You didn't research this well. There is a DoubleBuffered property in every Form. Try setting that to true. If you havn't overloaded anything on the form painting, then everything should work.

你这个没研究好。每个 Form 中都有一个 DoubleBuffered 属性。尝试将其设置为 true。如果您没有在表单绘制上超载任何内容,那么一切都应该正常工作。

回答by Steven A. Lowe

the short answer is

简短的回答是

SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

the long answer is: see MSDNor google

长答案是:见MSDN谷歌

just for fun, try calling Application.DoEvents() after each element is updated, and see if the problem gets better or worse ;-)

只是为了好玩,尝试在每个元素更新后调用 Application.DoEvents(),看看问题是变得更好还是更糟;-)

回答by DaveK

The ghosting is usually caused because you're running in a single thread and it's being held up with the field updates so the paint event doesnt fire. One way to fix this would be to put the heavy lifting in asynchronous methods. This will allow the form to repaint itself and update whatever is needed when they async method calls back.

重影通常是由于您在单个线程中运行而引起的,并且它被字段更新所阻止,因此不会触发绘制事件。解决此问题的一种方法是将繁重的工作放在异步方法中。这将允许表单重新绘制自身并在异步方法回调时更新所需的任何内容。

回答by FryHard

You could try to call this.SuspendLayout();before you start your update and this.ResumeLayout(false);when you have finished setting all the values in this way it should prevent the form from writing values one at a time.

您可以尝试调用this.SuspendLayout(); 在开始更新和this.ResumeLayout(false) 之前;当您以这种方式完成所有值的设置后,它应该可以防止表单一次写入一个值。

回答by Toji

You can double bufferalmost every windows forms control, although most of the time it requires that you inherit from the desired control and override a protected property. Be cautioned, though, that I've spent quite a bit of time on the same issue and I've yet to fully remove flicker on my more complex forms.

您可以双缓冲几乎每个 windows 窗体控件,尽管大多数时候它需要您从所需的控件继承并覆盖受保护的属性。但是请注意,我已经在同一问题上花费了相当多的时间,而且我还没有完全消除更复杂表单上的闪烁。

If you want truly flicker-free windows, I suggest looking at WPF.

如果您想要真正无闪烁的窗口,我建议您查看 WPF。

回答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 Brian Hasden

i had the same problem with OpenGLES, which is how i found this thread. of course i realize u are not using ogl, but maybe this helps u anyway ;)

我在 OpenGLES 上遇到了同样的问题,这就是我发现这个线程的方式。当然,我意识到你没有使用 ogl,但也许这对你有帮助;)

protected override void OnPaintBackground(PaintEventArgs e) { }

protected override void OnPaintBackground(PaintEventArgs e) { }

回答by John Suit

I know this question is old, but may be it will others searching for it in the future.

我知道这个问题很老,但将来其他人可能会搜索它。

DoubleBuffering doesn't always work well. To force the form to never flicker at all (but sometimes causes drawing issues):

DoubleBuffering 并不总是很好用。强制表单从不闪烁(但有时会导致绘图问题):

protected override CreateParams CreateParams
{
    get
    {
        CreateParams cp = base.CreateParams;
        cp.ExStyle |= 0x02000000; //WS_EX_COMPOSITED
        return cp;
    }
}

To stop flickering when a user resizes a form, but without messing up the drawing of controls (provided your form name is "Form1"):

要在用户调整表单大小时停止闪烁,但不会弄乱控件的绘制(假设您的表单名称是“Form1”):

int intOriginalExStyle = -1;
bool bEnableAntiFlicker = true;

public Form1()
{
    ToggleAntiFlicker(false);
    InitializeComponent();
    this.ResizeBegin += new EventHandler(Form1_ResizeBegin);
    this.ResizeEnd += new EventHandler(Form1_ResizeEnd);
}

protected override CreateParams CreateParams
{
    get
    {
        if (intOriginalExStyle == -1)
        {
            intOriginalExStyle = base.CreateParams.ExStyle;
        }
        CreateParams cp = base.CreateParams;

        if (bEnableAntiFlicker)
        {
            cp.ExStyle |= 0x02000000; //WS_EX_COMPOSITED
        }
        else
        {
            cp.ExStyle = intOriginalExStyle;
        }

        return cp;
    }
} 

private void Form1_ResizeBegin(object sender, EventArgs e)
{
    ToggleAntiFlicker(true);
}

private void Form1_ResizeEnd(object sender, EventArgs e)
{
    ToggleAntiFlicker(false);
}

private void ToggleAntiFlicker(bool Enable)
{
    bEnableAntiFlicker = Enable;
    //hacky, but works
    this.MaximizeBox = true;
}

回答by Josip Medved

You can just replace original control with custom one which has protected DoubleBuffered property to true. E.g. for ListView it would be something like this:

您可以将原始控件替换为将 DoubleBuffered 属性保护为 true 的自定义控件。例如,对于 ListView,它将是这样的:

internal class DoubleBufferedListView : ListView {

    public DoubleBufferedListView()
        : base() {
        this.DoubleBuffered = true;
    }

}

After that you just visit *.Designer.cs file and replace all mentions of native control with this one.

之后,您只需访问 *.Designer.cs 文件并用此文件替换所有提及的本机控件。

P.S. Instead of inheriting from control you can also set this property via reflection:

PS 除了从控件继承之外,您还可以通过反射设置此属性:

listView1.GetType().GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(lsvReport, true, null);

It is not clean nor recommended but it requires no changes in *.Designer.cs files.

它不干净也不推荐,但它不需要更改 *.Designer.cs 文件。

回答by Todd

It could also be caused by your coding, not the absence of doublebuffering. I came here just now with a similar problem but realised it's because:

它也可能是由您的编码引起的,而不是缺少双缓冲。我刚刚带着类似的问题来到这里,但意识到这是因为:

  1. I set a frame to invisible when an item is not selected.
  2. In between user selections, the index is cleared by the ListView control.
  3. I'm bound to the SelectedIndexChanged event
  1. 当未选择项目时,我将框架设置为不可见。
  2. 在用户选择之间,索引由 ListView 控件清除。
  3. 我绑定到 SelectedIndexChanged 事件

In other words:

换句话说:

  • User clicks item 1
    ~ SelectedIndexChanged(1)
  • User clicks item 2
    ~ SelectedIndexChanged(-1) <---- This causes the flicker
    ~ SelectedIndexChanged(2)
  • 用户点击项目 1
    ~ SelectedIndexChanged(1)
  • 用户单击项目 2
    ~ SelectedIndexChanged(-1) <---- 这会导致闪烁
    ~ SelectedIndexChanged(2)

So what's the solution? How to avoid thousands of needless ListView.SelectedIndexChanged events?

那么有什么解决办法呢?如何避免数千个不必要的 ListView.SelectedIndexChanged 事件?