我最近一直在开发一个应用程序,发现自己陷入了一个简单但烦人的问题。
当我输入其父级时,我想使特定控件可见/不可见,并且能够在此控件上执行事件(例如:单击)。问题是,当我输入我想要显示的控件时,鼠标悬停甚至对父节点不起作用。这导致我想要显示的控件闪烁(鼠标悬停工作 - &gt;控件显示 - &gt;鼠标悬停不再起作用 - &gt;控件隐藏 - &gt;鼠标悬停工作 - &gt;等)。< / p>
我找到了这个&#34;解决方案&#34;帮助我找到一些东西&#34;稳定&#34;。
// Timer to make the control appearing properly.
private void Timer_Elapsed(object o, ElapsedEventArgs e)
{
try
{
ItemToHideDisplay.Visible = true;
var mousePoint = this.PointToClient(Cursor.Position);
if (mousePoint.X > this.Width ||
mousePoint.X < 0 ||
mousePoint.Y > this.Height ||
mousePoint.Y < 0)
{
HideDisplayTimer.Stop();
ItemToHideDisplay.Visible = false;
base.OnMouseLeave(e);
}
}
catch
{
// We don't want the application to crash...
}
}
protected override void OnMouseEnter(EventArgs e)
{
HideDisplayTimer.Start();
base.OnMouseEnter(e);
}
基本上,当我输入对象时,如果鼠标在父对象中,则计时器启动并检查每50ms。如果是,则显示控件。如果没有,则停止计时器并隐藏控件。
这很有效。好极了。但我发现这个解决方案非常难看。
所以我的问题是:是否有另一种方法,另一种方法比这种方法更美观?
告诉我,如果我不够清楚:)
提前致谢!
编辑:嘿,我想我自己找到了它!诀窍是用以下方法覆盖父控件的OnMouseLeave:
protected override void OnMouseLeave(EventArgs e)
{
var mousePoint = this.PointToClient(Cursor.Position);
if (mousePoint.X > this.Width ||
mousePoint.X < 0 ||
mousePoint.Y > this.Height ||
mousePoint.Y < 0)
{
base.OnMouseLeave(e);
}
}
这样,当进入我显示的控件(进入父控件)时,不会触发鼠标离开事件! 它有效!
感谢您的回答。你可以继续发表我的想法,因为我在互联网上看不到很多解决方案:)
答案 0 :(得分:0)
你可以制作一个控制&#34;透明&#34;鼠标事件。所以鼠标事件只会通过它。
你必须编写自己的类继承你想要的控件。例如,如果Label
是您的特定控件,那么创建一个继承Label
的新类 - 您就明白了。 : - )
在新课程中,您可以使用窗口消息使控件忽略鼠标事件:
protected override void WndProc(ref Message m)
{
const int WM_NCHITTEST = 0x0084;
const int HTTRANSPARENT = -1;
switch(m.Msg)
{
case WM_NCHITTEST:
m.Result = (IntPtr)HTTRANSPARENT;
break;
default:
base.WndProc(ref m);
}
}
您可以阅读有关WndProc at MSDN的更多信息。
答案 1 :(得分:0)
您可以为表单注册邮件过滤器,并预处理表单的mouse move事件。多亏了这一点,您不必覆盖您的子控件等。
message filter一旦在父表单中注册,也将适用于子表单,因此即使表单的一部分被子表单覆盖,您的目标控件仍应显示/消失,具体取决于鼠标位置。
在以下示例中,表单上有一个面板,该面板内部有一个按钮。
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
internal void CaptureMouseMove(Point location)
{
if (panel1.RectangleToScreen(panel1.ClientRectangle).Contains(location))
{
button1.Visible = true;
Console.WriteLine(location + "in " + panel1.RectangleToScreen(panel1.ClientRectangle));
}
else
{
button1.Visible = false;
Console.WriteLine(location + "out " + panel1.RectangleToScreen(panel1.ClientRectangle));
}
}
internal bool Form1_ProcessMouseMove(Message m)
{
Point pos = new Point(m.LParam.ToInt32() & 0xffff, m.LParam.ToInt32() >> 16);
Control ctr = Control.FromHandle(m.HWnd);
if (ctr != null)
{
pos = ctr.PointToScreen(pos);
}
else
{
pos = this.PointToScreen(pos);
}
this.CaptureMouseMove(pos);
return false;
}
private MouseMoveMessageFilter mouseMessageFilter;
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
// add filter here
this.mouseMessageFilter = new MouseMoveMessageFilter();
this.mouseMessageFilter.TargetForm = this;
this.mouseMessageFilter.ProcessMouseMove = this.Form1_ProcessMouseMove;
Application.AddMessageFilter(this.mouseMessageFilter);
}
protected override void OnClosed(EventArgs e)
{
// remove filter here
Application.RemoveMessageFilter(this.mouseMessageFilter);
base.OnClosed(e);
}
private class MouseMoveMessageFilter : IMessageFilter
{
public Form TargetForm { get; set; }
public Func<Message, bool> ProcessMouseMove;
public bool PreFilterMessage(ref Message m)
{
if (TargetForm.IsDisposed) return false;
//WM_MOUSEMOVE
if (m.Msg == 0x0200)
{
if (ProcessMouseMove != null)
return ProcessMouseMove(m);
}
return false;
}
}
}
答案 2 :(得分:-1)
我会在这里做一个技巧:)我会将控件包装成一个新控件:)检查一下。
XAML:
<UserControl MouseEnter="Border_MouseEnter" MouseLeave="UserControl_MouseLeave" Margin="100" Background="Transparent">
<UserControl x:Name="ControlToHide" Background="Red">
<Button Content="hi" Width="100" Height="100"/>
</UserControl>
</UserControl>
代码背后:
private void Border_MouseEnter(object sender, MouseEventArgs e)
{
this.ControlToHide.Visibility = System.Windows.Visibility.Hidden;
}
private void UserControl_MouseLeave(object sender, MouseEventArgs e)
{
this.ControlToHide.Visibility = System.Windows.Visibility.Visible;
}
它轻巧,简单,有效。享受