6

作为自动注销的一部分,我们需要关闭子窗体。我们可以通过从计时器线程迭代 Application.OpenForms 来关闭子表单。我们无法使用 Application.OpenForms 关闭 OpenFileDialog/SaveFileDialog,因为 OpenFileDialog 未列出。

如何关闭 OpenFileDialog 和 CloseFileDialog?

4

4 回答 4

15

这将需要 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);
}
于 2012-08-23T12:58:53.723 回答
1

我不会在一个线程中关闭所有子表单,而是会引发每个子表单都可以/必须订阅的事件。在提高你的表格可以决定现在做什么。清理一些东西,保持状态,在表单范围内向服务器发送消息,您可以访问 openfiledialog 并尝试关闭它。

于 2012-08-23T11:42:18.653 回答
0

[解决方法] 这里是示例:

您应该定义完全透明的窗口 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);
    }
}
于 2012-08-23T13:03:17.600 回答
0

我的回答在概念上类似于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);
于 2019-01-15T23:52:32.040 回答