【问题标题】:How to prevent UI from redrawing every control one by one如何防止UI一一重绘每个控件
【发布时间】:2011-09-22 13:47:29
【问题描述】:

在我的用户控件中,我执行了一个冗长的操作。为了防止用户点击 UI,我显示了一个进度条并禁用了整个 UI,如下所示:

this.Enabled = false;
ShowProgressBar();
DoLengthyOperation();
RemoveProgressBar();
this.Enabled = true;

这工作正常。但是,我的用户控件上有许多其他控件,它们内部也有控件,它们内部也有控件,等等。

this.Enabled = false 

call 因此禁用了许多控件。这是故意的。但我遇到的问题是,您实际上可以看到 UI 一个一个地禁用每个控件。它运行得非常快,但是由于控件太多,您实际上可以看到它在所有控件中运行。这看起来不专业,它让屏幕闪烁,我的眼睛很痛。

有什么方法可以防止 UI 重绘,直到所有控件都被禁用,然后再执行一次重绘?

我希望这不是一个愚蠢的问题;)

不知道这是否相关:我的控件来自 DevExpress.XtraEditors.XtraUserControl。

【问题讨论】:

  • 我不知道它是否会有所帮助,但您可以在 this.Enabled = false; 之前尝试 this.SuspendLayout() 并在之后尝试 'this.ResumeLayout()`。这应该阻止一切处理布局更改。不过,我不确定启用/禁用是否被视为布局更改或绘画更改。否则,我认为您必须捕获并停止所有 OnPaint 事件。
  • 其实我认为我的问题是这个问题的重复:stackoverflow.com/questions/487661/…我还没有尝试过那个解决方案。

标签: c# winforms user-interface drawing


【解决方案1】:

你试过Form.SuspendLayout和Form.ResumeLayout吗?这似乎是你需要的。 msdn site here有更多信息。

在您想要重新绘制之前调用suspendlayout,然后在禁用所有控件后恢复。

this.SuspendLayout();
ShowProgressBar();
DoLengthyOperation();
RemoveProgressBar();
this.ResumeLayout();

如果进度条在表单上,​​您必须在暂停布局之前“显示”它。抱歉,我错过了。

【讨论】:

  • 如果您希望用户无法访问 UI,我同意 @bemused 关于显示对话框的评论。
  • 这没有任何作用。
【解决方案2】:

试试这个:

this.Invalidate();  // Invalidate the whole window
this.Enabled = false;
this.Refresh(); // Redraw every invalidated part of the window, so everything

【讨论】:

【解决方案3】:

这些建议解决方案似乎都不起作用。

我认为部分问题是我使用 DevExpress 并且每个控件不直接包含其子控件,而是使用 LayoutControlGroups 和 LayoutControls 和面板等。因此,实际使用的控件数量比您实际使用的控件高很多在屏幕上看到,需要禁用。

所以我只是添加了我自己的递归函数,它只禁用某些类型的控件,在我的例子中是按钮和编辑框。其余的只是忽略。这不仅更快,而且看起来也更好。一点闪烁都没有了。

我想我会使用这个解决方案,但我非常感谢在此提供答案或评论的每个人的努力,谢谢!

现在我发现我的问题似乎与这个问题重复:How do I suspend painting for a control and its children? 没有尝试过这个解决方案。

【讨论】:

    【解决方案4】:

    您可以尝试为控件添加双缓冲。这不会停止绘画。但是,它应该有助于解决问题的视觉部分。

    System.Reflection.PropertyInfo aProp =
            typeof(System.Windows.Forms.Control).GetProperty("DoubleBuffered",
            System.Reflection.BindingFlags.NonPublic |
            System.Reflection.BindingFlags.Instance);
     aProp.SetValue(YourControlNameHere, true, null);
    

    注意:大多数控件已经默认设置为 true。你的用户控件可能没有,所以你可以测试看看这是否有帮助。

    【讨论】:

    • 这与只是 DoubleBuffered = true; 不同吗?
    • BaGi:看起来是一样的,只是通过 .net 反射执行 :-)
    • DoubleBuffered = true 仅适用于某些控件...许多 Microsoft 控件都将该属性设置为受保护。所以你不能通过属性修改它。添加或删除项目时,我遇到了 ListView 控件闪烁的问题。
    【解决方案5】:

    您可以将控件放入容器中(称为 groupControls), 将容器的可见属性设置为 false, (出现启动屏幕或具有“更新”或任何可见的同等大小的容器 - 称之为 groupUpdateSplash) 更新您的控件 关闭启动容器可见并打开您的控制容器可见

    groupControls.visible = false
    groupUpdateSplash.visible = true
    /* update controls and everything */
    groupUpdateSplash.visible = false
    groupControls.visible = true
    

    【讨论】:

      猜你喜欢
      • 2021-10-24
      • 2011-03-05
      • 1970-01-01
      • 2016-09-02
      • 2012-05-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多