创建Winforms控件的句柄或第一次加载它时是否触发任何 static 事件?
这是一个人为的示例:
using (Form f1 = new Form())
{
f1.HandleCreated += (sender, args) => { MessageBox.Show("hi"); };
f1.ShowDialog();
}
using (Form f2 = new Form())
{
f2.HandleCreated += (sender, args) => { MessageBox.Show("hi"); };
f2.ShowDialog();
}
这就是我想要的:
Form.StaticHandleCreated += (sender, args) => { MessageBox.Show("hi"); };
using (Form f1 = new Form())
{
f1.ShowDialog();
}
using (Form f2 = new Form())
{
f2.ShowDialog();
}
(我要这样做是因为我有数百个控件,并且我需要自定义第三方控件的默认行为,而供应商没有提供更好的方法。他们专门说要处理OnLoad事件以进行自定义,但这是一个巨大的工作量。)
感谢xtu,这是工作版本,其保留表格的时间不会超过必要时间,以避免内存泄漏。
public class WinFormMonitor : IDisposable
{
private readonly IntPtr _eventHook;
private List<Form> _detectedForms = new List<Form>();
public event Action<Form> NewFormDetected;
private WinEventDelegate _winEventDelegate;
public WinFormMonitor()
{
_winEventDelegate = WinEventProc;
_eventHook = SetWinEventHook(
EVENT_OBJECT_CREATE,
EVENT_OBJECT_CREATE,
IntPtr.Zero,
_winEventDelegate,
0,
0,
WINEVENT_OUTOFCONTEXT);
}
public void Dispose()
{
_detectedForms.Clear();
UnhookWinEvent(_eventHook);
}
private void WinEventProc(IntPtr hWinEventHook, uint eventType,
IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
if (idObject != 0 || idChild != 0) return;
var currentForms = Application.OpenForms.OfType<Form>().ToList();
var newForms = currentForms.Except(_detectedForms);
foreach (var f in newForms)
{
NewFormDetected?.Invoke(f);
}
_detectedForms = currentForms;
}
private const uint EVENT_OBJECT_CREATE = 0x8000;
private const uint WINEVENT_OUTOFCONTEXT = 0;
private delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType,
IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
[DllImport("user32.dll")]
private static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr
hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess,
uint idThread, uint dwFlags);
[DllImport("user32.dll")]
private static extern bool UnhookWinEvent(IntPtr hWinEventHook);
}
答案 0 :(得分:3)
我受到this answer的启发,并使用SetWinEventHook
API创建了一个新的WinForm监视器。基本上,它监视EVENT_OBJECT_CREATE
事件并在发现新窗口时触发一个事件。
用法非常简单。您创建一个新实例,然后将处理程序附加到NewFormCreated
事件。这是一个示例:
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
using (var monitor = new WinFormMonitor())
{
monitor.NewFormCreated += (sender, form) => { MessageBox.Show($"hi {form.Text}"); };
Application.Run(new Form1());
}
}
这是WinFormMonitor
的来源:
public class WinFormMonitor : IDisposable
{
private readonly IntPtr _eventHook;
private readonly IList<int> _detectedFormHashes = new List<int>();
public event EventHandler<Form> NewFormCreated = (sender, form) => { };
public WinFormMonitor()
{
_eventHook = SetWinEventHook(
EVENT_OBJECT_CREATE,
EVENT_OBJECT_CREATE,
IntPtr.Zero,
WinEventProc,
0,
0,
WINEVENT_OUTOFCONTEXT);
}
public void Dispose()
{
_detectedFormHashes.Clear();
UnhookWinEvent(_eventHook);
}
private void WinEventProc(IntPtr hWinEventHook, uint eventType,
IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
// filter out non-HWND namechanges... (eg. items within a listbox)
if (idObject != 0 || idChild != 0) return;
if (!TryFindForm(hwnd, out var foundForm)) return;
RaiseIfNewFormFound(foundForm);
}
private void RaiseIfNewFormFound(Form foundForm)
{
var formHash = foundForm.GetHashCode();
if (_detectedFormHashes.Contains(formHash)) return;
NewFormCreated(this, foundForm);
_detectedFormHashes.Add(formHash);
}
private static bool TryFindForm(IntPtr handle, out Form foundForm)
{
foreach (Form openForm in Application.OpenForms)
{
if (openForm.Handle != handle) continue;
foundForm = openForm;
return true;
}
foundForm = null;
return false;
}
private const uint EVENT_OBJECT_CREATE = 0x8000;
private const uint WINEVENT_OUTOFCONTEXT = 0;
private delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType,
IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
[DllImport("user32.dll")]
private static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr
hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess,
uint idThread, uint dwFlags);
[DllImport("user32.dll")]
private static extern bool UnhookWinEvent(IntPtr hWinEventHook);
}