Geo*_*Cox 10 wpf mouse popup capture
我有一个类似于弹出窗口或菜单的控件.我想显示它,当用户点击框的边界外时,让它隐藏起来.我已经使用了Mouse.Capture(这个,CaptureMode.SubTree)以及在OnLostMouseCapture中以与Menu/Popup相同的方式重新获取捕获.
当用户在控件的边界外单击时,我在OnPreviewMouseDown中释放鼠标捕获.我没有把e.Handled设置为true.鼠标单击将转到主UI上的其他控件,但不会转到窗口的关闭按钮(红色X).它需要2次点击才能关闭应用.
有没有办法告诉WPF重新启动鼠标点击,或发送重复的鼠标点击事件?
这是我的代码.注意我将其重命名为MainMenuControl - 我没有构建菜单,因此Menu/MenuItem和Popup不是选项.
public class MainMenuControl : Control
{
static MainMenuControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MainMenuControl), new FrameworkPropertyMetadata(typeof(MainMenuControl)));
}
public MainMenuControl()
{
this.Loaded += new RoutedEventHandler(MainMenuControl_Loaded);
Mouse.AddPreviewMouseDownOutsideCapturedElementHandler(this, OnPreviewMouseDownOutsideCapturedElementHandler);
}
void MainMenuControl_Loaded(object sender, RoutedEventArgs e)
{
this.IsVisibleChanged += new DependencyPropertyChangedEventHandler(MainMenuControl_IsVisibleChanged);
}
void MainMenuControl_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (this.IsVisible)
{
Mouse.Capture(this, CaptureMode.SubTree);
Debug.WriteLine("Mouse.Capture");
}
}
// I was doing this in OnPreviewMouseDown, but changing to this didn't have any effect
private void OnPreviewMouseDownOutsideCapturedElementHandler(object sender, MouseButtonEventArgs e)
{
Debug.WriteLine("OnPreviewMouseDownOutsideCapturedElementHandler");
if (!this.IsMouseInBounds())
{
if (Mouse.Captured == this)
{
Mouse.Capture(this, CaptureMode.None);
Debug.WriteLine("Mouse.Capture released");
}
Debug.WriteLine("Close Menu");
}
}
protected override void OnLostMouseCapture(MouseEventArgs e)
{
base.OnLostMouseCapture(e);
Debug.WriteLine("OnLostMouseCapture");
MainMenuControl reference = e.Source as MainMenuControl;
if (Mouse.Captured != reference)
{
if (e.OriginalSource == reference)
{
if ((Mouse.Captured == null) || (!reference.IsAncestorOf(Mouse.Captured as DependencyObject)))
{
//TODO: Close
Debug.WriteLine("Close Menu");
}
}
// if a child caused use to lose the capture, then recapture.
else if (reference.IsAncestorOf(e.OriginalSource as DependencyObject))
{
if (Mouse.Captured == null)
{
Mouse.Capture(reference, CaptureMode.SubTree);
Debug.WriteLine("Mouse.Capture");
e.Handled = true;
}
}
else
{
//TODO: Close
Debug.WriteLine("Close Menu");
}
}
}
private bool IsMouseInBounds()
{
Point point = Mouse.GetPosition(this);
Rect bounds = new Rect(0, 0, this.Width, this.Height);
return bounds.Contains(point);
}
}
Run Code Online (Sandbox Code Playgroud)
问题是你正在谈论的鼠标处理是在WPF事件系统和操作系统的一部分之外,所以我们真的在谈论两个完全不同的鼠标消息队列,这些队列在大多数情况下都能很好地交互,但在这些边缘情况下我们看到互操作性并不完美.
您可以尝试生成Win32鼠标消息或向您自己的窗口发送关闭消息,但所有这些方法都是黑客攻击.由于弹出窗口和菜单表现出与您描述的完全相同的症状,因此看起来似乎没有一种简单的方法可以实现您所描述的内容.
相反,我建议您考虑在鼠标离开窗口的北客户区域或其他一些启发式(例如距控件指定距离)时放弃鼠标捕获.我知道这可能并不理想,但如果你想要关闭按钮工作得非常糟糕,这可能是一个令人满意的妥协.