Reputation: 577
I have a user control with a scrollbar (scrollbar appears as a contained user control, which inherits from Panel, is too large). When using the mouse to scroll all is well, but trying to scroll with the mousewheel dont work.
My solution here is to set focus to my child-control in an eventhandler for Scroll
. This works. Now the question; Will this result in a lot of unecessary calls to childControl.Focus()
? Is there a more neat way of doing this?
Edit: I think I was a bit unclear with my question so Rephrasing the question:
is
private void ChildControl_OnScroll(object sender, ScrollEventArgs scrollEventArgs)
{
this.childControl.Focus();
}
a bad way of setting the focus? I.e. will the focus be set mutliple times each time I scroll? or rather, will this cause (tiny) performance issues.
Upvotes: 0
Views: 616
Reputation: 39122
Here's another approach that gives focus when the scrollbar area of panel1 inside SomeUserControl is clicked. It uses NativeWindow so you don't have to change the panel in your UserControl. This way Focus() will only be called once, when the mouse goes down in the scrollbar area:
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);
}
}
}
This might be overkill for your scenario, but it demonstrates one way to trap lower level messages. As said before, you could also derive from Panel to achieve the same affect. You could also trap messages at the application level with IMessageFilter.
Upvotes: 1
Reputation: 39122
If childControl has a MouseEnter() event then use that instead:
private void childControl_MouseEnter(object sender, EventArgs e)
{
childControl.Focus();
}
Then the mouse wheel events should be direct to childControl.
Upvotes: 0
Reputation: 941317
The MouseWheel event is an event that "bubbles". Windows sends it to the control that has the focus, regardless of where the mouse cursor is located. The most typical problem is that you have a control that cannot receive the focus. A Panel for example.
This changes when you put a control on the panel. Now that control can get the focus and gets the MouseWheel message. It won't have any use for it so the message passes to its parent. Which does have a use for it, the panel scrolls as expected.
You can get a focusable panel control from this answer. A generic "make it work like a browser or Office program" solution from this question
Upvotes: 1