Могу ли я узнать в родительской форме, подписалась ли унаследованная форма на событие Show? - PullRequest
1 голос
/ 02 мая 2019

У меня есть следующие формы в моей структуре winforms

  • FormBase (унаследовано от Form)
  • FormBaseList (унаследовано от FormBase)
  • FormBaseDetail (унаследовано от FormBase)

Теперь каждая форма в приложении наследуется от одного из 3 выше.
Например, FormCustomerList будет наследоваться от FormBaseList

Теперь в FormBaseList присутствует событие FormBaseList_Shown (если дважды щелкнуть по нему в окне свойств в VS)

Что я хотел бы знать в коде из FormBaseList_Show, так это наличие события FormCustomerList_Show (снова, дважды щелкнув по нему в окне свойств).

Это вообще возможно?

Так почему я хочу этого?
Поскольку некоторые изменения в каркасе требуют, чтобы формы больше не использовали событие Shown, а пользовательское событие.
Я бы хотел поймать и показать предупреждение разработчику, если он добавляет в форму событие Show, и если оно действительно необходимо, он может установить свойство, которое будет скрывать это предупреждение.
Это предупреждениене нужно показывать во время разработки, во время выполнения будет достаточно.Но если это возможно во время разработки, это было бы бонусом.
Так можно ли это сделать, и, может быть, есть лучший способ сделать это?

Надеюсь, это объяснение понятно

EDIT

Идея состоит в том, что, когда разработчик использует событие Show, он должен получить предупреждение (либо во время разработки, либо во время выполнения).Если он чувствует, что ему действительно нужен метод Show, он должен иметь возможность отключить предупреждение для этой конкретной формы

Ответы [ 4 ]

1 голос
/ 03 мая 2019

Чтобы вызвать исключение или показать окно сообщения во время выполнения, у вас есть следующие опции:

  • Затенение события Shown, а в части add, исключение (если толькоустановлен флаг пропуска).
  • Используя отражение, найдите список обработчиков событий для события Shown и проверьте, есть ли обработчик, присоединенный к событию.

В обоих решенияхлогическое свойство может использоваться для переопределения поведения в производных формах.

Вариант 1 - Отображение события теневого копирования и добавление кода в add

Вы можете затенитьСобытие Shown и в метод доступа add добавьте код для отображения окна сообщения или выбросите исключение, если к событию добавлен обработчик.

В следующем примере я добавил свойство ThrowExceptionOnSubscribingShownEvent в базовую форму, которое по умолчанию равно true, что означает исключение при подписке на событие Shown.

public bool ThorwExceptionOnSubscribingShownEvent { get; set; } = true;

public new event EventHandler Shown
{
    add
    {
        if (ThorwExceptionOnSubscribingShownEvent)
            throw new InvalidOperationException("Shown event is deprecated.");

        base.Shown += value;
    }
    remove
    {
        base.Shown -= value;
    }
}

Вариант 2 - Поиск списка обработчиков событий для Shown события

В качестве опции для времени выполнения вы можете переопределить метод OnShown и, используя отражение, получить EVENT_SHOWNполе и, используя его, получите список обработчиков события Shown.Затем вы можете проверить, не является ли список обработчиков событий пустым, сгенерировать исключение.

В следующем примере я добавил свойство ThrowExceptionOnSubscribingShownEvent к базовой форме, которое по умолчанию равно true, что означает, что оно вызывает исключение при подписке на событие Shown.Вы можете установить его на false при необходимости в производных формах:

public partial class BaseForm : Form
{
    public BaseForm()
    {
        InitializeComponent();
    }

    public bool ThrowExceptionOnSubscribingShownEvent { get; set; } = true;
    protected override void OnShown(EventArgs e)
    {
        if (!DesignMode)
        {
            var EVENT_SHOWN = typeof(Form).GetField("EVENT_SHOWN",
                BindingFlags.NonPublic | BindingFlags.Static)
                .GetValue(null);
            var handlers = Events[EVENT_SHOWN]?.GetInvocationList();
            if (ThrowExceptionOnSubscribingShownEvent && handlers?.Length > 0)
                throw new InvalidOperationException("Shown event is deprecated.");
        }
        base.OnShown(e);
    }
}
1 голос
/ 03 мая 2019

Вы должны скрыть событие Shown и осудить его следующим образом:

[Obsolete("Shown event is deprecated.")]
public new event EventHandler Shown
{
    add { base.Shown += value; }
    remove { base.Shown -= value; }
}

Вы отметили его как устаревшее, и оно будет отображать предупреждение в окне Список ошибок во время компиляции при создании решения.

Также событие будет продолжать работать, как и ожидалось, подписавшись на исходное Shown событие базы.

Чтобы отключить предупреждение, добавьте следующую строку кода вверху файла designer.cs формы, подписавшейся на событие:

#pragma warning disable CS0618 // Type or member is obsolete

и добавьте эту строку внизу:

#pragma warning restore CS0618 // Type or member is obsolete

Примечание: В других файлах, кроме файла designer.cs, достаточно окружить только подписку обработчика событий на #pragma. Но для designer.cs вы не можете окружить подписку обработчика событий, потому что при изменении чего-либо в конструкторе, содержимое InitializeComponent и блок кода, который определяет переменные-члены, будут автоматически сгенерированы, и все ваши ручные изменения в designer.cs будет потеряно Но если вы поместите #pragma вверху и внизу файла, это безопасно и не будет удалено из файла designer.cs.

0 голосов
/ 02 мая 2019

В дополнение к ответу Брайса Вагнера вы можете скрыть событие Shown от показа в окне свойств и редакторе:

    [Obsolete("Don't use this event, use my custom one")]
    [System.ComponentModel.EditorBrowsable(EditorBrowsableState.Never)] // Hide from editor
    [System.ComponentModel.Browsable(false)] // Hide from properties window
    public new event EventHandler Shown;

Кажется, что EditorBrowsable работает только с DLL, импортированными из другого решения

0 голосов
/ 02 мая 2019

Возможно, возможно, с помощью отражения, но это было бы довольно грязно. Лучшей тактикой было бы скрыть показанное событие следующим образом:

        [Obsolete("Don't use this event, use my custom one")]
        public new event EventHandler Shown;

Тогда все, что пытается использовать это событие, будет генерировать предупреждения компилятора.

...