我有一个带滚动条的用户控件(滚动条显示为包含的用户控件,它继承自Panel,太大了)。当使用鼠标滚动一切都很好,但尝试使用鼠标滚动滚动不工作。
我的解决方案是在Scroll
的事件处理程序中将焦点设置为我的子控件。这有效。现在的问题;这会导致对childControl.Focus()
的大量不必要的调用吗?有没有更简洁的方法呢?
编辑:我认为我对我的问题有点不清楚所以重新提出问题:
是
private void ChildControl_OnScroll(object sender, ScrollEventArgs scrollEventArgs)
{
this.childControl.Focus();
}
设定焦点的不好方法?即每次滚动时焦点都会设置多次吗?或者说,这会导致(微小的)性能问题。
答案 0 :(得分:1)
MouseWheel事件是“气泡”的事件。无论鼠标光标位于何处,Windows都会将其发送到具有焦点的控件。最典型的问题是你有一个无法获得焦点的控件。例如,小组。
当您在面板上放置控件时,这会发生变化。现在该控件可以获得焦点并获取MouseWheel消息。它没有任何用处,因此消息传递给它的父节点。哪个 可以使用它,面板按预期滚动。
您可以从this answer获得可聚焦的面板控件。来自this question
的通用“使其像浏览器或Office程序一样工作”解决方案答案 1 :(得分: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在应用程序级别捕获消息。
答案 2 :(得分:0)
如果childControl有一个MouseEnter()事件,那么请改用它:
private void childControl_MouseEnter(object sender, EventArgs e)
{
childControl.Focus();
}
然后鼠标滚轮事件应直接发送到childControl。