代码之家  ›  专栏  ›  技术社区  ›  J Cooper

Winforms:有没有一种方法可以在我的应用程序中打开表单时得到通知?

  •  0
  • J Cooper  · 技术社区  · 15 年前

    (我知道,如果此功能位于菜单项中,我可以在单击菜单时简单地执行Application.OpenForms检查,但此按钮不在菜单中。)

    3 回复  |  直到 15 年前
        1
  •  1
  •   Hasani Blackwell    5 年前

    你可以用一个 MessageFilter 并监视WM_SHOWWINDOW和WM_CLOSE消息。

    https://blogs.msdn.microsoft.com/calvin_hsia/2016/11/30/its-easy-to-use-windows-hooks-even-from-c/

    下面是在窗体打开或关闭时写入控制台的代码。

    
    using System;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;
    
    namespace WindowsFormsApp1
    {
        class Form1 : Form
        {
            public Form1()
            {
                var newWindowBtn = new Button { Text = "New Window" };
                newWindowBtn.Click += (s, e) => new Form { Text = Guid.NewGuid().ToString() }.Show(this);
                Controls.Add(newWindowBtn);
            }
        }
    
        static class NativeMethods
        {
            [StructLayout(LayoutKind.Sequential)]
            public struct CWPSTRUCT
            {
                public IntPtr lparam;
                public IntPtr wparam;
                public int message;
                public IntPtr hwnd;
            }
    
            public delegate IntPtr CBTProc(int code, IntPtr wParam, IntPtr lParam);
    
            public enum HookType
            {
                WH_CALLWNDPROC = 4,
            }
    
            [DllImport("user32.dll")]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool UnhookWindowsHookEx(IntPtr hookPtr);
    
            [DllImport("kernel32.dll")]
            public static extern uint GetCurrentThreadId();
    
            [DllImport("user32.dll")]
            public static extern IntPtr CallNextHookEx(IntPtr hookPtr, int nCode, IntPtr wordParam, IntPtr longParam);
    
            [DllImport("user32.dll")]
            public static extern IntPtr SetWindowsHookEx(HookType hookType, CBTProc hookProc, IntPtr instancePtr, uint threadID);
        }
    
        static class Program
        {
            [STAThread]
            static void Main()
            {
                var hook = NativeMethods.SetWindowsHookEx(NativeMethods.HookType.WH_CALLWNDPROC, Callback, IntPtr.Zero, NativeMethods.GetCurrentThreadId());
                try
                {
                    Application.Run(new Form1());
                }
                finally
                {
                    NativeMethods.UnhookWindowsHookEx(hook);
                }
            }
    
            static IntPtr Callback(int code, IntPtr wParam, IntPtr lParam)
            {
                var msg = Marshal.PtrToStructure(lParam);
                if (msg.message == 0x0018)//WM_SHOWWINDOW
                {
                    var form = Control.FromHandle(msg.hwnd) as Form;
                    if (form != null)
                    {
                        Console.WriteLine($"Opened form [{form.Handle}|{form.Text}]");
                    }
                }
                if (msg.message == 0x0010)//WM_CLOSE
                {
                    var form = Control.FromHandle(msg.hwnd) as Form;
                    if (form != null)
                    {
                        Console.WriteLine($"Closed form [{form.Handle}|{form.Text}]");
                    }
                }
                return NativeMethods.CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
            }
        }
    }
    
        2
  •  2
  •   Philip Wallace    15 年前

    您可以定义自己的类型 FooForm Form . 在 ,激发一个静态定义的 FormOpened 事件

    食品形式 而不是 形式 . 每次打开一个窗体时都会触发该事件。

        3
  •  2
  •   jasonh    15 年前

    我最终构建了一个窗口管理器类,当创建一个新表单时,它会将自己添加到窗口管理器的集合中。您可以将此功能封装在一个基表单类中,这样您就不必记得这样做了。然后,您可以在窗口管理器类中创建事件来通知您类似的情况。您还可以在manager类中查询窗口集合。然后,我使用这个类将构建打开窗口菜单的功能整合到实用程序类中。

        4
  •  0
  •   Theodor Zoulias    5 年前

    一个简单的全局窗体计数器:

    public static class AppForms
    {
        public static int OpenForms { get; private set; }
        public static event EventHandler FormShown;
        public static event EventHandler FormClosed;
        public static void Watch(Form form)
        {
            form.Shown += (sender, e) => { OpenForms++; FormShown?.Invoke(sender, e); };
            form.Closed += (sender, e) => { OpenForms--; FormClosed?.Invoke(sender, e); };
        }
    }
    

    下一步是对项目进行项目宽度搜索 InitializeComponent

    InitializeComponent();
    AppForms.Watch(this);
    

    最后订阅全球活动 FormShown FormClosed 在主窗体的构造函数中。

    AppForms.FormShown += (sender, e) =>
    {
        this.Text = $"OpenForms: {AppForms.OpenForms}";
    };
    AppForms.FormClosed += (sender, e) =>
    {
        this.Text = $"OpenForms: {AppForms.OpenForms}";
    };
    

    您不必担心表单不会因为事件订阅而被垃圾收集。班级 AppForms Only the publishers keep references of subscribers .