wpf popup点击外部后自动关闭 自定义popup关闭逻辑
公共逻辑
private bool IsTouchWithinPopup(TouchPoint touchPoint, Popup popup)
{
if (popup.Child is FrameworkElement child)
{
// 获取Popup子元素的边界矩形
Rect bounds = new Rect(0, 0, child.ActualWidth, child.ActualHeight);
// 将触摸点坐标转换为相对于子元素的坐标
Point relativePoint = touchPoint.Position;
// 判断坐标是否在边界内
return bounds.Contains(relativePoint);
}
return false;
}
private bool IsTouchWithinPopup(Point touchPoint, Popup popup)
{
if (popup.Child is FrameworkElement child)
{
// 获取Popup子元素的边界矩形
Rect bounds = new Rect(0, 0, child.ActualWidth, child.ActualHeight);
// 将触摸点坐标转换为相对于子元素的坐标
Point relativePoint = touchPoint;
// 判断坐标是否在边界内
return bounds.Contains(relativePoint);
}
return false;
}
private bool IsTouchWithinBtn(Point touchPoint, Button popup)
{
if (popup is FrameworkElement child)
{
// 获取Popup子元素的边界矩形
Rect bounds = new Rect(0, 0, child.ActualWidth, child.ActualHeight);
// 将触摸点坐标转换为相对于子元素的坐标
Point relativePoint = touchPoint;
// 判断坐标是否在边界内
return bounds.Contains(relativePoint);
}
return false;
}
private bool IsTouchWithinBtn(TouchPoint touchPoint, Button popup)
{
if (popup is FrameworkElement child)
{
// 获取Popup子元素的边界矩形
Rect bounds = new Rect(0, 0, child.ActualWidth, child.ActualHeight);
// 将触摸点坐标转换为相对于子元素的坐标
Point relativePoint = touchPoint.Position;
// 判断坐标是否在边界内
return bounds.Contains(relativePoint);
}
return false;
}
鼠标点击逻辑
也可以实现打开popup时点击某些控件关闭popup,点击特殊的控件时不关闭popup。参考下面代码中的exceptBtnList
protected override void OnActivated(EventArgs e)
{
var popList = new List<Popup>() { popIsFirstPage, popIsLastPage, popIsFirstQuestion, popIsLastQuestion,
popExit, popSelectPen, popSelectErase, popClass, popWrongQuestion };
var exceptBtnList = new List<Button> { btnWrongQuestion, btnhignPreqWrongQuestion };
base.OnActivated(e);
InputManager.Current.PreProcessInput += (s, args) =>
{
if (args.StagingItem.Input is MouseEventArgs mouseEvent &&
mouseEvent.RoutedEvent == UIElement.PreviewMouseDownEvent)
{
foreach (var item in popList)
{
if (item.IsOpen)
{
// 判断是否点击在 Popup 外部
if (!IsTouchWithinPopup(mouseEvent.GetPosition(item.Child), item))
{
bool inBtn = false;
foreach (var btn in exceptBtnList)
{
inBtn = IsTouchWithinBtn(mouseEvent.GetPosition(btn), btn);
if (inBtn)
{
break;
}
}
if (inBtn)
{
continue;
}
item.IsOpen = false;
}
}
}
}
};
}
触摸逻辑
通过InputManager.Current.PreProcessInput在触摸事件执行前检测popup状态
如果点击在Popup外部则关闭
protected override void OnActivated(EventArgs e)
{
base.OnActivated(e);
InputManager.Current.PreProcessInput += (s, args) =>
{
if (args.StagingItem.Input is TouchEventArgs touchEvent &&
touchEvent.RoutedEvent == UIElement.PreviewTouchDownEvent)
{
var popList = new List<Popup>() { popIsFirstPage, popIsLastPage, popIsFirstQuestion, popIsLastQuestion,
popExit, popSelectPen, popSelectErase, popClass, popWrongQuestion };
foreach (var item in popList)
{
if (item.IsOpen)
{
// 判断是否点击在 Popup 外部
if (!IsTouchWithinPopup(touchEvent.GetTouchPoint(item.Child), item))
{
item.IsOpen = false;
}
}
}
}
};
}
private bool IsTouchWithinPopup(TouchPoint touchPoint, Popup popup)
{
if (popup.Child is FrameworkElement child)
{
// 获取Popup子元素的边界矩形
Rect bounds = new Rect(0, 0, child.ActualWidth, child.ActualHeight);
// 将触摸点坐标转换为相对于子元素的坐标
Point relativePoint = touchPoint.Position;
// 判断坐标是否在边界内
return bounds.Contains(relativePoint);
}
return false;
}
扩展
如果需要在其他界面中点击同时保证原来的窗口中的popup仍然是打开状态,就需要监控触发点击事件中的窗口句柄是否正确
// 添加Windows API声明
internal static class NativeMethods
{
[DllImport("user32.dll")]
public static extern IntPtr GetActiveWindow();
[DllImport("user32.dll")]
public static extern IntPtr WindowFromPoint(POINT point);
[DllImport("user32.dll")]
public static extern bool IsChild(IntPtr hWndParent, IntPtr hWnd);
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int X;
public int Y;
public POINT(int x, int y)
{
X = x;
Y = y;
}
public static implicit operator Point(POINT p)
{
return new Point(p.X, p.Y);
}
public static implicit operator POINT(Point p)
{
return new POINT((int)p.X, (int)p.Y);
}
}
}
//添加句柄检测
protected override void OnActivated(EventArgs e)
{
var popList = new List<Popup>() { popIsFirstPage, popIsLastPage, popIsFirstQuestion, popIsLastQuestion,
popExit, popSelectPen, popSelectErase, popClass, popWrongQuestion };
var exceptBtnList = new List<Button> { btnWrongQuestion, btnhignPreqWrongQuestion };
base.OnActivated(e);
// 获取当前窗口句柄
IntPtr hWnd = new WindowInteropHelper(this).Handle;
InputManager.Current.PreProcessInput += (s, args) =>
{
// 获取当前活动窗口句柄
IntPtr activeHwnd = NativeMethods.GetActiveWindow();
// 如果活动窗口不是当前窗口,不处理
if (activeHwnd != hWnd)
{
return;
}
if (args.StagingItem.Input is MouseEventArgs mouseEvent &&
mouseEvent.RoutedEvent == UIElement.PreviewMouseDownEvent)
{
foreach (var item in popList)
{
if (item.IsOpen)
{
// 判断是否点击在 Popup 外部
if (!IsTouchWithinPopup(mouseEvent.GetPosition(item.Child), item))
{
bool inBtn = false;
foreach (var btn in exceptBtnList)
{
inBtn = IsTouchWithinBtn(mouseEvent.GetPosition(btn), btn);
if (inBtn)
{
break;
}
}
if (inBtn)
{
continue;
}
item.IsOpen = false;
}
}
}
}
if (args.StagingItem.Input is TouchEventArgs touchEvent &&
touchEvent.RoutedEvent == UIElement.PreviewTouchDownEvent)
{
foreach (var item in popList)
{
if (item.IsOpen)
{
// 判断是否点击在 Popup 外部
if (!IsTouchWithinPopup(touchEvent.GetTouchPoint(item.Child), item))
{
bool inBtn = false;
foreach (var btn in exceptBtnList)
{
inBtn = IsTouchWithinBtn(touchEvent.GetTouchPoint(btn), btn);
if (inBtn)
{
break;
}
}
if (inBtn)
{
continue;
}
item.IsOpen = false;
}
}
}
}
};
}
留待后查,同时方便他人
联系我:ivesbao@163.com
联系我:ivesbao@163.com

浙公网安备 33010602011771号