User control resize [duplicate]

2019-08-02 01:56发布

Possible Duplicate:
“ResizeEnd” equivalent for usercontrols

I feel stupid, but I can't find a solution to a problem that I think it's easy.
I have a user control that (basically) shows an image drawing it during onPaint stage:

protected override void OnPaint(PaintEventArgs e)
{
    if (img != null)
        e.Graphics.DrawImage(img, ...);
}

When user control is resized, it must perform many actions and one is (given a particular condition) resize image to fit width or height, etc...
Image showed can be "heavy", so when user start resizing and moves mouse, the result is a sort of slow movement that's not good for end user.
So I'm wondering if there are windows messages reporting me that the resize operation is starting or completed: if so I can stop redrawing when resize starts and repaint image when resize ends.
Thanks to everybody

EDITED:
I tried this:

protected override void WndProc(ref Message m)
{
    const int WM_ENTERSIZEMOVE = 0x0231;
    const int WM_EXITSIZEMOVE = 0x0232;
    switch (m.Msg)
    {
        case WM_ENTERSIZEMOVE: resizing = true; break;
        case WM_EXITSIZEMOVE: resizing = false; break;
    }
}

but those messages are never called :(

标签: c# events resize
4条回答
走好不送
2楼-- · 2019-08-02 02:22

You might be interested by the Form.ResizeBegin and Form.ResizeEnd events.

If you're using WPF, this thread on MSDN might interest you. WPF requires hackery to know when the resize begins/ends

EDIT

Didn't noticed it was an UserControl ! This question seems to address your problem: "ResizeEnd" equivalent for usercontrols

查看更多
爱情/是我丢掉的垃圾
3楼-- · 2019-08-02 02:26

You really want to do that (windows messages)? :D

First, you cant do that like overriding PreProcessMessage or WndProc because I'm guessing the containing form will trap the resizing start/end message (or any other messages) so your control will not get any. The way to do that is to implement IMessageFilter interface on your control. Then you will get this method in your control in which you can switch through the received message m:

public bool PreFilterMessage(ref Message m)

Then at the control constructor add: Application.AddMessageFilter(this); and there you go, now Application thread is calling PreFilterMessage method and passing it the received message.

Another idea:

If you let the users change the controls size with their mouse, you can trap MouseDown and set bool MouseIsDown flag Then in OnResize you can check

if(MouseIsDown && Resizing == false)
{
    Resizing = true;
    //Start Resizing only once
}

And on MouseUp:

if(Resizing == true && MouseIsDown == true)
{
    Resizing = MouseIsDown = false;
    //End the resizing once
}
查看更多
贪生不怕死
4楼-- · 2019-08-02 02:26

I post an answer after a long investigation.
First of all I want to thank everybody for your contribution, because your suggestions led me to the right way. Thanks to @Hans Passant too, because his solution on this post is an important piece.

THE PROBLEM:

  • assume we have a usercontrol named innCnt (inner control) contained in another usercontrol named outCnt (outer control), which in turn should be placed in a form we don't develop (so we can't edit its source)
  • assume we have to catch the EndResize event in innCnt

CONTRIBUTES:

  • Using PreProcessMessage or overriding WndProc (thanks to @Cipi):
    I tried these solutions, but I don't receive WM_ENTERSIZEMOVE and WM_EXITSIZEMOVE messages from Windows
  • Trap MouseDown and OnResize events (thanks to @Cipi):
    It could be ok, but that logic should be moved on outCnt because innCnt could not receive MouseDown if user is resizing out control or form.
    Anyway I don't like too much this solution
  • In the Load event of innCnt, hook event handlers to the control's form's events (thanks to @hometoast and @pikzen):
    I tried this solution (and the one provided by @Hans here) but this doesn't work because when innCnt is loaded, even in if not in DesignMode, his parent is a part of outCnt, whose parent is null because not ready set!!

SOLUTION:
Basicly I had to move @Hans logic inside outCnt but not in Load event, because even here parent is still null!

public class OuterControl
{
    protected override void OnParentChanged(EventArgs e)
    {
        if (!this.DesignMode)
        {
            Form form = this.FindForm();
            if (form != null)
            {
                form.ResizeBegin += (s, ea) =>innerCnt.Resizing = true;
                form.ResizeEnd += (s, ea) => innerCnt.Resizing = false;
            }
        }
        base.OnParentChanged(e);
    }
}

public class InnerControl
{
    private bool resizing = false;

    public bool Resizing { 
        get { return resizing; }; 
        set {
            resizing = value;
            if (!resizing) {
                // Resizing is just finished:
                // let's do what we need
            }
        }
    }

    protected override void OnResize(EventArgs e)
    {
        if (Resizing)
        {
            base.OnResize(e);
            return;
        }
        else
        {
            // Perform resizing actions
        }
    }
}

KNOWN PROBLEMS:
I'm quite sure that if outCnt is placed inside another usercontrol, solution provided won't work...

查看更多
孤傲高冷的网名
5楼-- · 2019-08-02 02:33

In the Load event of your UserControl, hook event handlers to the control's form's events.

Apologies, I have a VB project open, I'll convert it in the answer when I get a moment.

Private Sub UserControl1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    AddHandler Me.FindForm.ResizeBegin, AddressOf MyFormsResizeBegin
    AddHandler Me.FindForm.ResizeEnd, AddressOf MyFormsResizeEnd
End Sub

Private Sub MyFormsResizeBegin(sender As Object, e As EventArgs)
    'tell your control to wait.
End Sub
Private Sub MyFormsResizeEnd(sender As Object, e As EventArgs)
    'say everything is ok to continue

End Sub
查看更多
登录 后发表回答