zoukankan      html  css  js  c++  java
  • C#自动弹出窗口并定时自动关闭

    最近做个小项目,用到一个小功能:后台线程定时查询数据库,不符合条件的记录弹出消息提醒(在窗口最前面),并且过几秒钟再自动关闭弹出的窗口。

    所以从网上找来资料,如下:

    WinForm 下实现一个自动关闭的MessageBox

    Author: eaglet
          WinForm 下我们可以调用MessageBox.Show 来显示一个消息对话框,提示用户确认等操作。在有些应用中我们需要通过程序来自动关闭这个消息对话框而不是由用户点击确认按钮来关闭。然而.Net framework 没有为我们提供自动关闭MessageBox 的方法,要实现这个功能,我们需要使用Window API 来完成。
          首先我们需要找到这个消息对话框的窗口句柄,一个比较简单的方法就是用 FindWindow API 来查找对应的窗体句柄。

            [DllImport("user32.dll", SetLastError = true)]
            static extern IntPtr FindWindow(string lpClassName, string lpWindowName);


          这个API调用可以通过窗口的类名或者窗口标题的名字来查找窗口句柄。

          接下来我们还需要找到一个 API 来关闭对话框,这里我使用 EndDialog

            [DllImport("user32.dll")]
            static extern bool EndDialog(IntPtr hDlg, out IntPtr nResult);


          有了这两个API函数,我们就可以来关闭消息对话框了。思路是在调用MessageBox.Show 前启动一个后台工作线程,这个工作线程等待一定时间后开始查找消息对话框的窗口句柄,找到后调用EndDialog API 函数关闭这个消息对话框。不过这个方法有个问题,就是如果同时又多个同名的消息对话框(可能不一定是这个应用的),这样做可能会关错窗口,如何解决这个问题,我还没有想出比较好的方法,如果大家有更好的方法解决这个问题,不妨一起讨论讨论。
         
          我根据这个思路编写了延时关闭消息对话框的函数

    复制代码
            public void ShowMessageBoxTimeout(string text, string caption, 
                MessageBoxButtons buttons, int timeout)
            {
                ThreadPool.QueueUserWorkItem(new WaitCallback(CloseMessageBox), 
                    new CloseState(caption, timeout));
                MessageBox.Show(text, caption,buttons);
            }
    复制代码


       这个函数中timeout 参数单位是毫秒,其他参数和MessageBox.Show的参数含义是一样的,这里不再详细说明。
       这个函数中首先利用线程池调用一个工作线程 CloseMessageBox ,并将对话框的标题和延时时间通过CloseState这个类传递给CloseMessageBox函数。
       CloseState 的定义如下:
       

    复制代码
            private class CloseState
            {
                private int _Timeout;

                /// <summary>
                /// In millisecond
                /// </summary>
                public int Timeout
                {
                    get
                    {
                        return _Timeout;
                    }
                }

                private string _Caption;

                /// <summary>
                /// Caption of dialog
                /// </summary>
                public string Caption
                {
                    get
                    {
                        return _Caption;
                    }
                }

                public CloseState(string caption, int timeout)
                {
                    _Timeout = timeout;
                    _Caption = caption;
                }
            }
     


    最后就是CloseMessageBox函数了,直接看代码吧

    复制代码
    复制代码
            private void CloseMessageBox(object state)
            {
                CloseState closeState = state as CloseState;

                Thread.Sleep(closeState.Timeout);
                IntPtr dlg = FindWindow(null, closeState.Caption);

                if (dlg != IntPtr.Zero)
                {
                    IntPtr result;
                    EndDialog(dlg, out result);
                }
            }
    复制代码
    复制代码
     
    出处:http://www.cnblogs.com/XGLSummer/archive/2012/09/06/2673334.html
    =============================================================================================
    发现上面的代码是可以,但弹出的窗口没有在最前面,所以还需要继续找资料。

    在屏幕的最前面弹一个消息框

    有人要说了,弹一个ShowDialog不就完了吗?!或者MessageBox.Show("saaaaa");就可以达到目的。
    但你要看到下面的情况,你就不这样说了。
    我在C#中创建了一个Excel,每当我编辑一个值的时候,都会用C#代码判断这些值是否是有效的,当无效进就提醒他们。我用的就是MessageBox.Show("aaaaaaa");
    但它不一定弹在最前面,因为它是C#的代码,故当Excel在最前面时,那个消息框是不能显示在最头面的。

    用以下方法可以解决此问题:
    MessageBox.Show("要弹的信息。", "信息", MessageBoxButtons.OK, MessageBoxIcon.Information,MessageBoxDefaultButton.Button1, essageBoxOptions.DefaultDesktopOnly);

    呵呵,虽然还是那个MessageBox.Show,但很多人都不知道呀。大家可以试试。

     
    出处:http://www.cnblogs.com/pnljs/archive/2012/09/19/2694182.html
    ========================================================================================================
    使用上面的代码,可以实现弹出窗口在最上面,但是结合第一段的代码,无法正常关闭,直接报错了。说明调用的static extern bool EndDialog(IntPtr hDlg, out IntPtr nResult);方法不能正常关闭窗口,那么咱们再重新找个可以关闭窗口的API函数把。在网上找到如下代码:
        public const int WM_CLOSE = 0x10;
     
        [System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "SendMessageA")]
        public static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);
    private void button1_Click(object sender, System.EventArgs e) { IntPtr hwnd_win; hwnd_win = FindWindow(null, "要找的窗体名"); SendMessage(hwnd_win, WM_CLOSE, 0, 0); }

    查找窗口函数:

            //查找窗体
            [DllImport("User32.dll", EntryPoint = "FindWindow")]
            private static extern int FindWindow(string lpClassName, string lpWindowName);
            static void Main()
            {
                 //@Form1根据窗体的Text文本值获得窗体
                    int WINDOW_HANDLER = FindWindow(null, @"Form1");
             }
    出处:http://bbs.csdn.net/topics/340065537/
    =======================================================================================
     
    通过以上几步,我们现在可以正常的实现了我们文章开头提到的功能了。
     
  • 相关阅读:
    WinForm里保存TreeView状态
    动态规划 回溯和较难题
    go 基本链表操作
    leetcode 42接雨水
    leetcode 旋转数组搜索
    leetcode 牛客编程 子序列 树 数组(积累)
    剑指offer(积累)
    go快排计算最小k个数和第k大的数
    leetcode 打家劫舍
    leetcode 字符串相关问题
  • 原文地址:https://www.cnblogs.com/mq0036/p/6502798.html
Copyright © 2011-2022 走看看