【问题标题】:User control resize [duplicate]用户控件调整大小[重复]
【发布时间】:2018-07-20 15:17:35
【问题描述】:

可能重复:
“ResizeEnd” equivalent for usercontrols

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

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

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

已编辑:
我试过这个:

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

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

【问题讨论】:

  • 我可以假设您的控件已调整大小,因为它停靠在正在调整大小的面板或表单上吗?
  • @hometoast: 是的,但我不控制容器形式...我的控制将被其他人使用...

标签: c# events resize


【解决方案1】:

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

如果您使用的是 WPF,您可能会对这个 thread on MSDN 感兴趣。 WPF 要求骇客知道调整大小的开始/结束时间

编辑

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

【讨论】:

  • 这是一个用户控件,而不是一个表单...
  • Marco,对,但是您的用户控件必须驻留在表单上。您可以让您的用户控件订阅表单事件。
  • @hometoast:你能举个例子吗?我从来没有这样做过。而且,我的用户控件包含在另一个用户控件中:这会改变什么吗?
  • @Marco:也许This是你感兴趣的。
  • 特别是检查是否处于设计模式的部分!
【解决方案2】:

您真的想这样做(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】:

在 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

【讨论】:

  • 感谢您的回答,但正如我之前提到的,我的容器不是表单,我的用户控件将交给其他人,所以我不能强制他们这样做任何事物;而且我不知道谁是我的父母......
  • 不是直接容器,不。但最终,用户控件(以及它的父级)必须驻留在表单上。 FindForm() 方法正是用于此目的。不知道你有多少层 .Parent()
  • 阅读我的解决方案并告诉我你的想法。非常感谢您的帮助,非常感谢!
【解决方案4】:

经过长时间的调查,我发布了答案。
首先,我要感谢大家的贡献,因为您的建议使我走上了正确的道路。还要感谢@Hans Passant,因为他在this post 上的解决方案很重要。

问题:

  • 假设我们有一个名为 innCnt(内部控件)的用户控件包含在另一个名为 outCnt(外部控件)的用户控件中,而该控件又应放置在我们不使用的表单中'不开发(所以我们不能编辑它的源代码)
  • 假设我们必须在 innCnt 中捕获 EndResize 事件

贡献:

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

解决方案:
基本上我必须在 outCnt 中移动 @Hans 逻辑,但不能在 Load 事件中移动,因为即使在这里 parent 仍然为空!

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

【讨论】:

  • ParentChanged 事件只被调用一次......除非你正在编写非常奇怪的代码。您的解决方案仍然取决于表单的 resize/begin.end 事件处理程序。用于可能无用的内部控件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-30
相关资源
最近更新 更多