首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Winforms静态HandleCreated或OnLoad事件

Winforms静态HandleCreated或OnLoad事件
EN

Stack Overflow用户
提问于 2018-11-06 07:37:25
回答 1查看 235关注 0票数 2

在为Winforms控件创建句柄或首次加载句柄时,是否会触发任何静态事件?

这是一个人为的例子:

代码语言:javascript
复制
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();
}

这就是我想要的

代码语言:javascript
复制
Form.StaticHandleCreated += (sender, args) => { MessageBox.Show("hi"); };
using (Form f1 = new Form())
{
    f1.ShowDialog();
}
using (Form f2 = new Form())
{
    f2.ShowDialog();
}

(我希望这样做,因为我有几百个控件,我需要自定义第三方控件的默认行为,而供应商没有提供更好的方法。他们专门说要处理OnLoad事件来进行定制,但是这是一个巨大的工作负载。)

多亏了xtu,这里的工作版本不会占用表单超过必要的时间,以避免内存泄漏。

代码语言:javascript
复制
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);
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-11-06 12:13:32

我受到this answer的启发,使用SetWinEventHook API创建了一个新的WinForm监视器。基本上,只要找到一个新窗口,它就监视EVENT_OBJECT_CREATE事件并触发一个事件。

用法很简单。创建一个新实例,然后将处理程序附加到NewFormCreated事件。下面是一个示例:

代码语言:javascript
复制
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的来源

代码语言:javascript
复制
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);
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53167570

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档