我有一个Panel地方AutoScroll是真实的。该面板包含许多较小的面板,它们像瓷砖一样填充所有可用空间。当有太多子面板需要显示时,我会按预期获得垂直滚动条。
每个“图块”都绑定了一些事件处理程序来处理 MouseDown / MouseUp / MouseMove,因为它们可以拖动。
我遇到的问题是鼠标滚轮滚动在父面板上不起作用,因为它没有焦点。我无法给它焦点,因为很可能我会在移动具有焦点的子面板时滚动,即使如此,也需要解决方法,因为面板不喜欢焦点。
我一直在尝试(但失败了)找到一种仅将鼠标滚轮事件从子级传播到父级的方法。
我读过,在 Winforms 中,如果一个控件无法处理鼠标事件,它会将其冒泡到该控件的父级,然后到该控件的父级,依此类推,直到找到合适的处理程序。
考虑到这一点,我认为最好的解决方案是用于WndProc覆盖子面板上的所有滚动相关事件,并将它们传递给父级,同时保持所有其他事件完好无损,但不可否认,这不是我的强项,我迷路了。
我尝试了一些其他解决方案,例如使子面板对所有鼠标事件不可见,但正如您可能已经猜到的那样,这很糟糕。我读过有关实现消息过滤器的信息,但不理解它。
下面的代码将为您提供面板及其子面板的非常基本的示例:
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;
}
Run Code Online (Sandbox Code Playgroud)
这是我在自定义面板中重写 WndProc 的尝试:
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);
}
Run Code Online (Sandbox Code Playgroud)
非常欢迎任何帮助或替代方法。谢谢!
小智 6
在我这边@a-clymer的解决方案不起作用,也许环境不同。目前我的问题没有直接、明确的答案,所以我尝试结合其他专业人士的想法并取得成功。
在我当前的项目中,我在面板中包含一些输入控件。我设法通过创建 ComboBox 的子类并覆盖其 WndProc 来使鼠标滚轮滚动面板而不是 ComboBox 项目:
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 /sf/answers/1373267031/
SendMessage(this.Parent.Handle, m.Msg, m.WParam, m.LParam);
m.Result = IntPtr.Zero;
}else base.WndProc(ref m);
}
}
Run Code Online (Sandbox Code Playgroud)
所有功劳都归于汉斯·帕桑特(再次),取自他建议的线程:https ://stackoverflow.com/a/3562449/17034
让包含面板获得焦点效果很好。对于上面的演示代码,该类不需要更改,只需将其用于包含面板即可。我必须对我的项目进行一些调整,以便在必要时调用焦点,但这远不是火箭科学。
再次感谢。
| 归档时间: |
|
| 查看次数: |
4160 次 |
| 最近记录: |