I have a Panel
where AutoScroll
is true. This panel contains many smaller panels that fill all available space like tiles. When there are too many sub-panels to display I get the vertical scroll bar as expected.
Each of these "tiles" have some event handlers tied to them to handle MouseDown / MouseUp / MouseMove as they can be dragged around.
The problem I'm having is that mouse wheel scroll doesn't work on the parent panel as it won't have focus. I can't give it focus because in all probability I'll be scrolling while moving a sub-panel which will have the focus instead, and even then that would require workarounds since panels don't like focus.
I've been trying (and failing) to find a way to propagate only mousewheel events from the children to the parent.
I've read that in Winforms if a control cannot handle a mouse event it will bubble it up to the parent of that control, and then to the parent of that control and so on until it finds a suitable handler.
With this in mind I figured the best solution would be to use WndProc
to override all scroll related events on the sub-panel and pass them to the parent while leaving all other events intact but admittedly this isn't my strong suit and I'm lost.
I've tried a few other solutions such as making the sub-panels invisible to all mouse events but as you might have guessed this was bad. I've read about implementing a message filter but didn't understand it.
Here's the code that will give you a very basic example of the panel and its children:
private void Form1_Load(object sender, EventArgs e)
{
Height = 600;
Width = 300;
Color[] colors = new Color[]{ Color.PowderBlue, Color.PeachPuff };
Panel panel = new Panel()
{
Height = this.ClientSize.Height - 20,
Width = 200,
Top = 10,
Left = 10,
BackColor = Color.White,
BorderStyle = BorderStyle.FixedSingle,
AutoScroll = true
};
for (int i = 0; i < 10; i++)
{
Panel subPanel = new Panel()
{
Name = @"SubPanel " + i.ToString(),
Height = 100,
Width = panel.Width - System.Windows.Forms.SystemInformation.VerticalScrollBarWidth - 2,
BackColor = colors[i % 2],
Top = i * 100
};
subPanel.MouseClick += subPanel_MouseClick;
panel.Controls.Add(subPanel);
}
Controls.Add(panel);
}
void subPanel_MouseClick(object sender, MouseEventArgs e)
{
Panel panel = sender as Panel;
Text = panel.Name;
}
Here's my attempt at overriding WndProc in a custom panel:
class NoScrollPanel : Panel
{
private const int WM_HSCROLL = 0x114;
private const int WM_VSCROLL = 0x115;
private const int MOUSEWHEEL = 0x020A;
private const int KEYDOWN = 0x0100;
protected override void WndProc(ref Message m)
{
if ((m.HWnd == Handle) && (m.Msg == MOUSEWHEEL || m.Msg == WM_VSCROLL || (m.Msg == KEYDOWN && (m.WParam == (IntPtr)40 || m.WParam == (IntPtr)35))))
{
PostMessage(Parent.Handle, m.Msg, m.WParam, m.LParam);
}
else
{
base.WndProc(ref m);
}
}
[DllImport("User32.dll")]
private static extern IntPtr PostMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
}
Any help or alternative approaches are most welcome. Thanks!
At my side @a-clymer's solution does not work, perhaps different environment. Currently there is no direct, clear answer for my problem so I try to combine several thoughts of other professionals and succeed.
In my current project, I have a few input controls contained in a Panel. I managed to make the mouse wheel scroll the panel instead of the ComboBox items by creating a child class of ComboBox and override its WndProc:
public class ComboBoxWithParentMouseWheel : ComboBox
{
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
const int WM_MOUSEWHEEL = 0x020A;
//thanks to a-clymer's solution
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_MOUSEWHEEL)
{
//directly send the message to parent without processing it
//according to https://stackoverflow.com/a/19618100
SendMessage(this.Parent.Handle, m.Msg, m.WParam, m.LParam);
m.Result = IntPtr.Zero;
}else base.WndProc(ref m);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With