Winforms: Есть ли способ получать информацию, когда форма открывается в моем приложении? - PullRequest
2 голосов
/ 22 октября 2009

В главной форме у меня есть кнопка «Перейти к окну», которую я хотел бы включить только тогда, когда открыты другие окна (в моем приложении). Есть ли какое-то событие, которое возникает при открытии или закрытии формы, которую может перехватить моя основная форма? (Например, возможно, какой-то способ отследить, когда Application.OpenForms изменился?)

(Я понимаю, что если бы эта функция была в пункте меню, я мог бы просто выполнить проверку Application.OpenForms при нажатии на меню, но эта кнопка отсутствует в меню.)

Ответы [ 4 ]

2 голосов
/ 22 октября 2009

Я закончил создание класса оконного менеджера и, когда создается новая форма, он добавляет себя в коллекцию оконного менеджера. Вы можете инкапсулировать эту функциональность в базовом классе Form, так что вам не нужно забывать делать это. Затем вы можете создавать события в классе оконного менеджера, чтобы уведомлять вас о подобных вещах. Вы также получаете возможность запрашивать коллекцию окон в классе менеджера. Затем я использовал этот класс, чтобы иметь возможность объединить функциональность, которая создает меню открытых окон, в служебный класс.

2 голосов
/ 22 октября 2009

Вы можете определить свой собственный тип FooForm, который наследуется от Form. В конструкторе FooForm запустите статически определенное событие FormOpened.

Тогда все ваши формы будут иметь базовый тип FooForm вместо Form. Событие будет запускаться каждый раз, когда открывается одна из ваших форм.

1 голос
/ 22 октября 2009

Вы можете использовать MessageFilter и отслеживать сообщения WM_SHOWWINDOW и WM_CLOSE.

ОБНОВЛЕНИЕ: Вы также можете использовать хук Windows, аналогичный тому, что в 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);
        }
    }
}
0 голосов
/ 06 апреля 2019

Простой глобальный счетчик форм:

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 является подписчиком, и подписчики не сохраняют ссылки издателей. Только издатели хранят отзывы подписчиков .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...