【发布时间】:2018-11-06 07:37:25
【问题描述】:
在创建 Winforms 控件的句柄或首次加载它时是否会触发任何 静态 事件?
这是一个人为的例子:
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);
}
【问题讨论】:
-
在Form基类中实现这个怎么样?那么任何继承 Form 基类的 Form 都会以这种方式运行。
-
这是一个选项 - 在解决方案中查找和替换会起作用,但我希望有一个更易于维护的选项,因为当我们制作新的 UserControl 时,我们需要记住使用另一个班级。
-
不,没有静态事件,但是这个问题有两种不同的解决方案 - 一种是创建一个基本表单,其中每个具有这些控件的表单都继承自它,另一种是将所有自定义代码封装在不同的类中,并在包含这些控件的所有表单中引用它。没有更多细节,我更喜欢第二种选择。
-
@ZoharPeled,是的,我们经常使用后者,但是当我们添加新控件时,我们必须始终记住添加装饰器。我估计在过去的一年中我花了 8 个小时来寻找缺少装饰器的控件并为它们创建票证。我希望有一些“有效”的东西。
-
一年中的 8 小时似乎并不多....