views:

266

answers:

4

I need to redraw a control after it was resized and not while it is being resized because it takes a lot of time to redraw a control and it wastes a lot of resources.

My control inherits Control class and I'm overriding the OnResize event.

PS: OnSizeChanged is absolutely the same

+2  A: 

One solution can be resizeing your control only after the parent control/form finished resizeing. You can do this using the 'ResizeEnd` event.

For example:

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");
}
Am
As nobugz pointed out, this is asking for trouble; a control should not know anything specific about its parent, it's entirely possible that it doesn't even *have* a parent (at least temporarily). This may be convenient but it also breaks one of the most fundamental rules of abstractions, which is not to have reverse dependencies.
Aaronaught
A: 

How about when you get the MouseDown event go: YourControl.SuspendLayout();

and then in the MouseUp event go: YourControl.ResumeLayout();

Shnitzel
A: 

ResizeEnd event seems the best idea, but as an alternative you could have a timer, which you restart in the resize event, and redraw when the timer fires. As long as the time of the timer is fairly short, say 100ms then you shouldn't notice the redraw delay too badly.

But the other event seems like a better option...

Sam Holder
+1  A: 

Let me present an alternative view of this problem:

The issue is not necessarily that the "user is still resizing the control." The real issue is that the control is being resized more frequently than the time it takes to redraw.

If you define the problem as one of throughput, it becomes easier to solve. And in fact Bebop had the right idea with his answer, but I think we can do better:

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();
    }
}

The idea here is to have the control actively profile itself; if you run it on a slow machine or the machine is simply running sluggishly then this will slow down its redraw rate. If you're running it on bleeding-edge hardware then it may not have to skip any redraws at all. This is actually a fairly simple "auto frame skip" algorithm of the kind you often see in device emulators.

To be clear, I have nothing against the approach advocated by nobugz; the only reason I would choose this one instead is that the logic is completely self-contained, whereas exposing a Resizing property (or perhaps a more aptly-named EnableFullPaint) is depending on the consumer to know and use it properly - and also, it prevents any repainting for the entire duration of the resize, which may cause the app to "feel" buggy - users don't tend to expect a blank/nonsense screen during a resize operation.

I've used both methods and they both work; which one is best for you depends on your requirements. I suggest you try this, see how well it works for you, and if it becomes problematic or isn't what you want then go with nobugz' answer.

Aaronaught
+1. What I meant to say :)
Sam Holder