0

我有一个带有滚动条的用户控件(滚动条显示为包含的用户控件,它继承自 Panel,太大)。使用鼠标滚动时一切正常,但尝试使用鼠标滚轮滚动不起作用。

我的解决方案是在事件处理程序中将焦点设置为我的子控件Scroll。这行得通。现在的问题;这会导致很多不必要的调用childControl.Focus()吗?有没有更简洁的方法来做到这一点?

编辑:我认为我的问题有点不清楚,所以重新表述问题:

private void ChildControl_OnScroll(object sender, ScrollEventArgs scrollEventArgs) 
{
    this.childControl.Focus();
}

设置焦点的不好方法?即每次滚动时焦点都会设置多次吗?或者更确切地说,这会导致(微小的)性能问题。

4

3 回答 3

1

MouseWheel 事件是一个“冒泡”事件。无论鼠标光标位于何处,Windows 都会将其发送到具有焦点的控件。最典型的问题是你有一个无法接收焦点的控件。以面板为例。

当您将控件放在面板上时,这种情况会发生变化。现在该控件可以获得焦点并获得 MouseWheel 消息。它没有任何用处,因此消息传递给它的父级。哪个确实有用,面板按预期滚动。

您可以从此答案中获得可聚焦的面板控件。此问题的通用“使其像浏览器或 Office 程序一样工作”解决方案

于 2013-05-07T15:47:33.303 回答
1

这是另一种方法,当单击 SomeUserControl 内的 panel1 的滚动条区域时提供焦点。它使用 NativeWindow,因此您不必更改 UserControl 中的面板。这样,当鼠标在滚动条区域向下时,Focus() 只会被调用一次:

public partial class SomeUserControl : UserControl
{
    private TrapMouseDownOnScrollArea trapScroll = null;

    public SomeUserControl()
    {
        InitializeComponent();
        this.VisibleChanged += new EventHandler(SomeUserControl_VisibleChanged);
    }

    void SomeUserControl_VisibleChanged(object sender, EventArgs e)
    {
        if (this.Visible && trapScroll == null)
        {
            trapScroll = new TrapMouseDownOnScrollArea(this.panel1);
        }
    }

    private class TrapMouseDownOnScrollArea : NativeWindow
    {
        private Control control = null;
        private const int WM_NCLBUTTONDOWN = 0xA1;

        public TrapMouseDownOnScrollArea(Control ctl)
        {
            if (ctl != null && ctl.IsHandleCreated)
            {
                this.control = ctl;
                this.AssignHandle(ctl.Handle);
            }
        }

        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case WM_NCLBUTTONDOWN:
                    if (this.control != null)
                    {
                        Rectangle screenBounds = control.RectangleToScreen(new Rectangle(0, 0, control.Width, control.Height));
                        if (screenBounds.Contains(Cursor.Position))
                        {
                            control.Focus();
                        }
                    }

                    break;
            }
            base.WndProc(ref m);
        }

    }

}

这对于您的场景可能有点过分,但它演示了一种捕获较低级别消息的方法。如前所述,您也可以从 Panel 派生以获得相同的效果。您还可以使用 IMessageFilter 在应用程序级别捕获消息。

于 2013-05-07T20:04:23.463 回答
0

如果 childControl 有一个 MouseEnter() 事件,那么使用它来代替:

    private void childControl_MouseEnter(object sender, EventArgs e)
    {
        childControl.Focus();
    }

那么鼠标滚轮事件应该直接指向childControl。

于 2013-05-07T16:03:16.323 回答