【问题标题】:How to check if the resize is still in progress with OnResize event?如何使用 OnResize 事件检查调整大小是否仍在进行中?
【发布时间】:2010-01-24 16:29:03
【问题描述】:

我需要在调整大小后重绘控件,而不是在调整大小时重绘控件,因为重绘控件需要大量时间并且浪费大量资源。

我的控件继承了 Control 类,并且我将覆盖 OnResize 事件。

PS: OnSizeChanged 完全一样

【问题讨论】:

    标签: c# events controls resize redraw


    【解决方案1】:

    当你得到 MouseDown 事件时怎么样: YourControl.SuspendLayout();

    然后在 MouseUp 事件中执行: YourControl.ResumeLayout();

    【讨论】:

    • 我认为即使经过这么长时间,这种方法也值得评论。我喜欢这种方法的原因是我认为当用户将显示选项设置为仅在移动表单时显示窗口框架时它会很好用,这在处理慢速连接和慢速重绘时间时会很有帮助。在调整大小期间不重绘表单的控件将适合这种情况。
    【解决方案2】:

    让我提出这个问题的另一种观点:

    问题不一定是“用户仍在调整控件的大小”。真正的问题是控件调整大小的频率比重绘所需的时间更频繁。

    如果您将问题定义为吞吐量之一,它会变得更容易解决。事实上,Bebop 的回答是正确的,但我认为我们可以做得更好:

    public class MyControl : Control
    {
        private TimeSpan paintTime = 250;   // Time to paint, default=250ms
        private TimeSpan resizeTime = 100;  // Time to update layout, default=100ms
    
        protected override void OnPaint(PaintEventArgs pe)
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            // Do your painting here, or call base.OnPaint
            sw.Stop();
            paintTime = sw.Elapsed;
        }
    
        protected override void OnResize(EventArgs e)
        {
            // The "Stop" is not redundant - it will force the timer to "reset"
            // if it is already running.
            resizeTimer.Stop();
            base.OnResize(e);
            resizeTimer.Interval =
                (int)(paintTime.TotalMilliseconds + resizeTime.TotalMilliseconds);
            resizeTimer.Start();
        }
    
        private void UpdateSize()
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            // Resizing code goes here
            sw.Stop();
            resizeTime = sw.Elapsed;
        }
    
        private void resizeTimer_Tick(object sender, EventArgs e)
        {
            resizeTimer.Stop();
            UpdateSize();
        }
    }
    

    这里的想法是让控件主动配置自己;如果您在慢速机器上运行它,或者机器只是运行缓慢,那么这将减慢它的重绘速度。如果您在尖端硬件上运行它,那么它可能根本不需要跳过任何重绘。这实际上是您在设备模拟器中经常看到的那种相当简单的“自动跳帧”算法。

    需要明确的是,我并不反对 nobugz 提倡的方法;我选择这个的唯一原因是逻辑是完全独立的,而暴露Resizing 属性(或者可能更贴切地命名EnableFullPaint)取决于消费者了解和正确使用它 -而且,它可以防止在调整大小的整个过程中任何重新绘制,这可能会导致应用“感觉”有问题 - 用户在调整大小操作期间不会期望出现空白/无意义的屏幕。

    我用过这两种方法,它们都有效;哪一个最适合您取决于您​​的要求。我建议你试试这个,看看它对你的效果如何,如果它变得有问题或者不是你想要的,那么请使用 nobugz 的答案。

    【讨论】:

    • 我认为在调整大小期间完全不重绘表单的选项非常适合配置为在桌面上移动窗口时仅绘制窗口框架的系统。话虽如此,我喜欢这种方法,因为它是自我分析的,不需要表单提供额外的事件支持。起初我认为这有点矫枉过正——只是传递 ResizeEnd 事件没什么大不了的,但在分发给其他人的大型程序中,它实际上是最好的方法。我计划很快将其合并。
    【解决方案3】:

    只有在父控件/窗体完成调整大小后,才能调整控件的大小。您可以使用“ResizeEnd”事件来做到这一点。

    例如:

    private void UserControl1_Load(object sender, EventArgs e)
    {
        ((Form)this.Parent).ResizeEnd += new EventHandler(UserControl1_ResizeEnd);
    }
    void UserControl1_ResizeEnd(object sender, EventArgs e)
    {
        MessageBox.Show("Resize end");
    }
    

    【讨论】:

    • 正如 nobugz 指出的那样,这是自找麻烦;控件不应该知道任何关于其父级的具体信息,它甚至完全有可能没有 父级(至少暂时如此)。这可能很方便,但它也打破了抽象的最基本规则之一,即不具有反向依赖关系。
    【解决方案4】:

    ResizeEnd 事件似乎是最好的主意,但作为替代方案,您可以有一个计时器,您可以在 resize 事件中重新启动它,并在计时器触发时重绘。只要计时器的时间相当短,比如 100 毫秒,那么您应该不会太严重地注意到重绘延迟。

    但其他活动似乎是更好的选择......

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-29
      • 1970-01-01
      • 2011-12-26
      • 1970-01-01
      相关资源
      最近更新 更多