我想让所有打开的弹出窗口(使用StaysOpen == false)从代码中关闭。基本上我想模拟用户点击代码鼠标(这会关闭弹出窗口)。
我不需要实际模拟点击,我只需要产生的行为。我想过只是通过视觉树寻找弹出窗口并关闭每个弹出窗口,但这似乎不是最干净的方法。
提前感谢您的任何帮助或意见。
答案 0 :(得分:9)
WPF弹出窗口实际上创建了一个新窗口(Win32窗口,而不是WPF Window
实例)。因此,您无法在Application.Windows
集合中找到它,但您可以使用EnumChildWindows
等Win32 API找到它。
获得句柄后,您可以检索关联的HwndSource
。我认为RootVisual
的{{1}}是HwndSource
(没有检查,您可能需要更深入地查看可视树)。
所以代码应该与此类似(完全未经测试):
Popup
答案 1 :(得分:1)
通过可视化树是这样做的方式,它不依赖于你如何创建它们的方式。可能有更清洁的方法,但它们都取决于您的实施。
例如,我的应用程序中的所有弹出窗口都必须查看模型对象,这些对象会暴露Popup绑定的某种IsOpen
属性。如果我需要在我的项目中实现这个功能,我只需要维护这些对象(或生成器方法)的集合,我可以迭代它们,并在每个对象上设置IsOpen
为false。如果你不像我那样构建你的UI,这显然是行不通的。
答案 2 :(得分:1)
被接受的答案(https://stackoverflow.com/a/3886139/12885902)并非对我有用,因为source.RootVisual
的类型从不为Popup
,而是内部类型为PopupRoot
。以下调整使代码起作用:
private void CloseAllPopups()
{
foreach (Window window in Application.Current.Windows)
{
IntPtr handle = new WindowInteropHelper(window).Handle;
EnumThreadWindows(handle, ClosePopup, IntPtr.Zero);
}
}
private static bool ClosePopup(IntPtr hwnd, IntPtr lParam)
{
HwndSource source = HwndSource.FromHwnd(hwnd);
if (source?.RootVisual?.GetType().Name == "PopupRoot")
{
if (LogicalTreeHelper.GetParent(source.RootVisual) is Popup popup)
{
popup.IsOpen = false;
}
}
return true; // to continue enumeration
}
private delegate bool EnumWindowsProc(IntPtr hwnd, IntPtr lParam);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool EnumThreadWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam);
还请记住,必须由主UI线程(例如Application.Current.Dispatcher.Invoke()
)调用CloseAllPopups()方法!
答案 3 :(得分:0)
声明打开的弹出窗口的静态数组:
static List<Popup> openedPopups = new List<Popup>();
在打开弹出窗口之前关闭所有预先打开的弹出窗口:
private void TextBlock_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
// close all before opene popup
openedPopups.ForEach(p => p.IsOpen = false);
openedPopups.Clear(); // clear opened popus's collection, because they were closed
Popup1.IsOpen = true; // open popup I need open now
openedPopups.Add(Popup1); // remember it for future close
}
答案 4 :(得分:0)
我以前的回答也并非一直有效。仅当将Visual Studio调试器附加到该进程时,该函数才起作用。在任何情况下最终起作用的是以下内容:
Application.Current.Dispatcher.Invoke(() =>
{
PresentationSource.CurrentSources.OfType<HwndSource>()
.Select(h => h.RootVisual)
.OfType<FrameworkElement>()
.Select(f => f.Parent)
.OfType<Popup>()
.Where(popup => popup.IsOpen)
.ToList()
.ForEach(popup => popup.IsOpen = false);
});