专注于滚动

本文关键字:滚动 于滚动 专注 | 更新日期: 2023-09-27 18:12:43

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

我的解决方案是将焦点设置为Scroll的事件处理程序中的子控件。这个作品。现在的问题是;这会导致对childControl.Focus()的大量不必要的调用吗?有没有更简洁的方法?

编辑:我想我的问题有点不清楚,所以换个问题:

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

设置焦点的坏方法?也就是说,每次滚动时焦点会被设置多次吗?或者,这会导致(微小的)性能问题吗?

专注于滚动

这是另一种方法,当单击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在应用程序级别捕获消息。

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

当您在面板上放置控件时,这将发生变化。现在控件可以获得焦点并获得MouseWheel消息。它没有任何用处,所以消息传递给它的父节点。哪个有它的用处,面板按预期滚动。

你可以从这个答案得到一个可聚焦的面板控制。一个通用的"让它像浏览器或Office程序一样工作"的解决方案

如果childControl有MouseEnter()事件,则使用该事件:

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

那么鼠标滚轮事件应该直接给childControl.