作为自动注销的一部分,我们需要关闭子窗体。我们可以通过从计时器线程迭代 Application.OpenForms 来关闭子表单。我们无法使用 Application.OpenForms 关闭 OpenFileDialog/SaveFileDialog,因为 OpenFileDialog 未列出。
如何关闭 OpenFileDialog 和 CloseFileDialog?
这将需要 pinvoke,对话框不是表单,而是原生 Windows 对话框。基本方法是枚举所有顶层窗口并检查它们的类名是否为“#32770”,即 Windows 拥有的所有对话框的类名。并通过发送 WM_CLOSE 消息强制对话框关闭。
向您的项目添加一个新类并粘贴如下所示的代码。注销计时器到期时调用 DialogCloser.Execute()。 然后关闭表格。该代码适用于 MessageBox、OpenFormDialog、FolderBrowserDialog、PrintDialog、ColorDialog、FontDialog、PageSetupDialog 和 SaveFileDialog。
using System;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
static class DialogCloser {
public static void Execute() {
// Enumerate windows to find dialogs
EnumThreadWndProc callback = new EnumThreadWndProc(checkWindow);
EnumThreadWindows(GetCurrentThreadId(), callback, IntPtr.Zero);
GC.KeepAlive(callback);
}
private static bool checkWindow(IntPtr hWnd, IntPtr lp) {
// Checks if <hWnd> is a Windows dialog
StringBuilder sb = new StringBuilder(260);
GetClassName(hWnd, sb, sb.Capacity);
if (sb.ToString() == "#32770") {
// Close it by sending WM_CLOSE to the window
SendMessage(hWnd, 0x0010, IntPtr.Zero, IntPtr.Zero);
}
return true;
}
// P/Invoke declarations
private delegate bool EnumThreadWndProc(IntPtr hWnd, IntPtr lp);
[DllImport("user32.dll")]
private static extern bool EnumThreadWindows(int tid, EnumThreadWndProc callback, IntPtr lp);
[DllImport("kernel32.dll")]
private static extern int GetCurrentThreadId();
[DllImport("user32.dll")]
private static extern int GetClassName(IntPtr hWnd, StringBuilder buffer, int buflen);
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
}
我不会在一个线程中关闭所有子表单,而是会引发每个子表单都可以/必须订阅的事件。在提高你的表格可以决定现在做什么。清理一些东西,保持状态,在表单范围内向服务器发送消息,您可以访问 openfiledialog 并尝试关闭它。
[解决方法] 这里是示例:
您应该定义完全透明的窗口 ex。“运输”;
每次需要显示对话框时,都需要显示 TRANSP 并将 TRANSP 作为参数传递给 ShowDialog 方法。
当应用程序关闭时 - 调用 TRANSP 窗口的 Close() 方法。子对话框将关闭。
public partial class MainWindow : Window
{
OpenFileDialog dlg;
TranspWnd transpWnd;
public MainWindow()
{
InitializeComponent();
Timer t = new Timer();
t.Interval = 2500;
t.Elapsed += new ElapsedEventHandler(t_Elapsed);
t.Start();
}
void t_Elapsed(object sender, ElapsedEventArgs e)
{
Dispatcher.BeginInvoke(new Action(() =>
{
transpWnd.Close();
}), null);
}
private void button1_Click(object sender, RoutedEventArgs e)
{
transpWnd = new TranspWnd();
transpWnd.Visibility = System.Windows.Visibility.Hidden; //doesn't works right
transpWnd.Show();
dlg = new OpenFileDialog();
dlg.ShowDialog(transpWnd);
}
}
我的回答在概念上类似于Hans Passant 的回答。
但是,使用GetCurrentThreadId()
作为tid
参数EnumThreadWindows
对我不起作用,因为我是从另一个线程调用它。如果你正在这样做,那么要么枚举进程的线程 ID 并尝试每一个,直到找到所需的窗口:
ProcessThreadCollection currentThreads = Process.GetCurrentProcess().Threads;
foreach (ProcessThread thread in currentThreads) {
CloseAllDialogs(thread.Id);
}
ShowDialog
或保存执行以下操作的线程 ID CommonDialog
:
threadId = GetCurrentThreadId();
threadIds.Add(threadId);
result = dialog.ShowDialog()
threadIds.Remove(threadId);
进而:
foreach (int threadId in threadIds) {
CloseAllDialogs(threadId);
}
哪里CloseAllDialogs
看起来像:
public void CloseAllDialogs(int threadId) {
EnumThreadWndProc callback = new EnumThreadWndProc(checkIfHWNDPointsToWindowsDialog);
EnumThreadWindows(threadId, callback, IntPtr.Zero);
GC.KeepAlive(callback);
}
private bool checkIfHWNDPointsToWindowsDialog(IntPtr hWnd, IntPtr lp) {
StringBuilder sb = new StringBuilder(260);
GetClassName(hWnd, sb, sb.Capacity);
if (sb.ToString() == "#32770") {
SendMessage(hWnd, 0x0010, IntPtr.Zero, IntPtr.Zero);
}
return true;
}
private delegate bool EnumThreadWndProc(IntPtr hWnd, IntPtr lp);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool EnumThreadWindows(int tid, EnumThreadWndProc callback, IntPtr lp);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern int GetCurrentThreadId();
[DllImport("user32.dll", SetLastError = true)]
private static extern int GetClassName(IntPtr hWnd, StringBuilder buffer, int buflen);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);