用户控件调整大小

时间:2011-09-28 13:49:17

标签: c# events resize

  

可能重复:
  “ResizeEnd” equivalent for usercontrols

我感到愚蠢,但我找不到解决问题的方法,我觉得这很容易 我有一个用户控件(基本上)显示在 onPaint 阶段绘制它的图像:

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

当调整用户控件的大小时,它必须执行许多操作,其中一个是(给定特定条件)调整图像大小以适应宽度或高度等...
显示的图像可能“很重”,因此当用户开始调整大小并移动鼠标时,结果是一种慢速移动,这对最终用户不利。
所以我想知道是否有窗口消息报告我调整大小操作正在开始或完成:如果是这样我可以在调整大小时停止重绘并在调整大小结束时重新绘制图像。
感谢大家

编辑:
我试过这个:

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

但永远不会调用这些消息:(

4 个答案:

答案 0 :(得分:2)

您可能会对Form.ResizeBeginForm.ResizeEnd事件感兴趣。

如果您使用的是WPF,则此thread on MSDN可能会让您感兴趣。 WPF需要hackery才能知道调整大小何时开始/结束

修改

没有注意到它是UserControl!这个问题似乎解决了你的问题: "ResizeEnd" equivalent for usercontrols

答案 1 :(得分:2)

在UserControl的Load事件中,将事件处理程序挂钩到控件表单的事件。

道歉,我打开了一个VB项目,当我得到片刻时,我会在答案中将其转换。

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

答案 2 :(得分:1)

你真的想这样做(Windows消息)? :D

首先,您无法覆盖PreProcessMessageWndProc,因为我猜测包含的表单会捕获调整大小的开始/结束消息(或任何其他消息),因此您的控件将无法获取任何。这样做的方法是在您的控件上实现IMessageFilter接口。然后,您将在控件中获得此方法,您可以在其中切换收到的消息m:

public bool PreFilterMessage(ref Message m)

然后在控制构造函数中添加:Application.AddMessageFilter(this);然后你去,现在应用程序线程正在调用PreFilterMessage方法并将接收到的消息传递给它。

另一个想法:

如果您让用户使用鼠标更改控件大小,您可以捕获MouseDown并设置bool MouseIsDown标志然后在OnResize中您可以检查

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

在MouseUp上:

if(Resizing == true && MouseIsDown == true)
{
    Resizing = MouseIsDown = false;
    //End the resizing once
}

答案 3 :(得分:1)

经过长时间的调查,我发了一个答案 首先,我要感谢大家的贡献,因为你的建议让我以正确的方式前进。感谢@Hans Passant,因为他在this post上的解决方案是一个重要的部分。

问题:

  • 假设我们有一个名为 innCnt (内部控件)的用户控件包含在另一个名为 outCnt 的用户控件中(外部控件),而这个用户控件又应放在我们不用的表单中不发展(因此我们无法编辑其来源)
  • 假设我们必须抓住 innCnt中的EndResize事件

贡献:

  • 使用PreProcessMessage或覆盖WndProc(感谢@Cipi):
    我尝试了这些解决方案,但是我没有收到来自Windows的 WM_ENTERSIZEMOVE WM_EXITSIZEMOVE 消息
  • 陷阱MouseDownOnResize事件(感谢@Cipi):
    它可以是正常的,但是该逻辑应该在 outCnt 上移动,因为如果用户正在调整控件或窗体的大小, innCnt 将无法接收MouseDown。
    无论如何,我不太喜欢这个解决方案
  • innCnt Load事件中,将事件处理程序挂钩到控件表单的事件中(感谢@hometoast和@pikzen):
    我尝试了这个解决方案(以及@Hans here提供的解决方案),但这不起作用,因为当加载 innCnt 时,即使不在DesignMode中,他的父母也是如此是 outCnt 的一部分,其父为空,因为没有准备好设置!!

<强> SOLUTION:
基本上我不得不在 outCnt 中移动@Hans逻辑,而不是在Load事件中移动,因为即使在这里,父级仍为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
        }
    }
}

已知问题:
我很确定如果将 outCnt 放在另一个用户控件中,提供的解决方案将无效...