用户控件调整大小

本文关键字:调整 控件 用户 | 更新日期: 2023-09-27 18:09:51

可能重复:
“ResizeEnd;相当于用户控制

我觉得自己很愚蠢,但我找不到一个我认为简单的问题的解决方案
我有一个用户控件,它(基本上(显示了在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;
    }
}

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

用户控件调整大小

您可能对Form.ResizeBegin和Form.Resi泽End事件感兴趣。

如果您正在使用WPF,MSDN上的这个线程可能会引起您的兴趣。WPF要求黑客知道调整大小何时开始/结束

编辑

没有注意到这是一个UserControl!这个问题似乎解决了你的问题:"ResizeEnd";相当于用户控件

你真的想这么做(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
}

在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

经过长时间的调查,我发布了一个答案
首先,我要感谢大家的贡献,因为你们的建议使我走上了正确的道路。也感谢@Hans Passant,因为他在这篇帖子中的解决方案是一篇重要的文章。

问题:

  • 假设我们有一个名为innCnt(内部控件(的用户控件,包含在另一个名称为outCnt外部控件(的用户名控件中,而该用户名控件又应该以我们不开发的形式放置(因此我们无法编辑其源代码(
  • 假设我们必须在innCnt中捕获EndResize事件

贡献:

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

解决方案:
基本上,我不得不将@Hans逻辑移到outCnt中,但不能移到Load事件中,因为即使在这里,父级仍然为空!

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被放在另一个用户控件中,所提供的解决方案将不起作用。。。