我的主窗体上有一个“切换到窗口”按钮,只有当其他窗口(在我的应用程序中)打开时,我才会启用它。每当打开或关闭表单时,我的主表单可以挂钩,是否会出现某种事件? (例如,也许某种方式来跟踪Application.OpenForms何时发生了变化?)
(据我所知,如果此功能在菜单项中,我可以在单击菜单时执行Application.OpenForms检查,但此按钮不在菜单中。)
答案 0 :(得分:2)
您可以定义自己的FooForm
类型,该类型继承自Form
。在FooForm
的构造函数中,触发静态定义的FormOpened
事件。
然后,您的所有表单的基本类型都为FooForm
而不是Form
。每次打开一个表单时,都会触发该事件。
答案 1 :(得分:2)
我最终构建了一个窗口管理器类,当创建一个新窗体时,它会将自己添加到Window Manager的集合中。您可以将此功能封装在基本Form类中,这样您就不必记住这样做。然后,您可以在窗口管理器类中创建事件,以通知您这样的事情。您还可以在manager类中查询窗口集合。然后我使用这个类来将构建打开窗口菜单的功能整合到实用程序类中。
答案 2 :(得分:1)
您可以使用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);
}
}
}
答案 3 :(得分:0)
一个简单的全局表格计数器:
SELECT t.* FROM movies t
where main_menu_id=".$menu_id."
ORDER BY
DATE(t.rel_date) >= DATE(NOW()) DESC ,
IF(DATE(t.rel_date)<DATE(NOW()),t.rel_date,DATE(NULL)) DESC ,
t.rel_date ASC
下一步是对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}";
};
是订阅者,订阅者不保留发布者的引用。 Only the publishers keep references of subscribers。