Вызов событий C# из-за пределов класса-владельца?

Возможно ли это при каких-либо обстоятельствах?

Мои текущие обстоятельства таковы:

public class CustomForm : Form
{
    public class CustomGUIElement
    {
    ...
        public event MouseEventHandler Click;
        // etc, and so forth.
    ...
    }

    private List<CustomGUIElement> _elements;

    ...

    public void CustomForm_Click(object sender, MouseEventArgs e)
    {
        // we might want to call one of the _elements[n].Click in here
        // but we can't because we aren't in the same class.
    }
}

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

internal enum GUIElementHandlers { Click, ... }
internal void CustomGUIElement::CallHandler(GUIElementHandler h, object[] args) {
    switch (h) {
        case Click:
            this.Click(this, (EventArgs)args[0]);
            break;
        ... // etc and so forth
    }
}

Это ужасно уродливый кладж, но он должен работать ... Но должно ли быть более элегантное решение? Библиотека .NET делает это все время с обработчиками сообщений и вызывающими событиями в Control. Есть ли у кого-нибудь еще какие-нибудь идеи получше?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
15
0
20 815
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

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

Это сработает. Плохо, но это сработает. Сохранение списка обратных вызовов - это, по сути, то, что в любом случае делает событие. Зачем тратить силы на то, чтобы заново реализовать то, что уже есть?

Matthew Scharley 20.09.2008 16:00
Ответ принят как подходящий

Вам просто нужно добавить общедоступный метод для вызова события. Microsoft уже делает это для некоторых событий, таких как PerformClick, для элементов управления, которые открывают событие Нажмите.

public class CustomGUIElement    
{
    public void PerformClick()
    {
        OnClick(EventArgs.Empty);
    }

    protected virtual void OnClick(EventArgs e)
    {
        if (Click != null)
            Click(this, e);
    }
}

Затем вы должны сделать следующее внутри своего примера обработчика событий ...

public void CustomForm_Click(object sender, MouseEventArgs e)        
{
    _elements[0].PerformClick();
}

Я думаю, он может поднять событие не из класса событий?

Per Hornshøj-Schierbeck 20.09.2008 15:53

Вы вызываете PerformClick () вне класса событий.

Paul Batum 20.09.2008 15:54

Нет, это тот стиль, которым я хотел заниматься; т.е. вызов события из-за пределов класса события. Я просто надеялся, что есть способ избежать этого метода. Я полагаю, что я выберу внутреннее решение, которое я опубликовал, эта настраиваемая форма будет в DLL, поэтому внутренний материал будет скрыт.

Matthew Scharley 20.09.2008 15:57

Я бы выбрал более чистое решение, размещенное здесь, сделав PerformClick внутренним, если вы не хотите, чтобы он отображался. По моим ощущениям при использовании перечисления и метода CallHandler позже их будет труднее читать / поддерживать.

Craig Eddy 21.09.2008 18:23

Ключевое слово event в C# изменяет объявление делегата. Это предотвращает прямое назначение делегату (вы можете использовать только + = и - = в событии) и предотвращает вызов делегата извне класса.

Итак, вы можете изменить свой код, чтобы он выглядел так:

public class CustomGUIElement
{
...
    public MouseEventHandler Click;
    // etc, and so forth.
...
}

Затем вы можете вызвать событие извне класса следующим образом.

myCustomGUIElement.Click(sender,args);

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

myCustomGUIElement.Click = null;

что недопустимо, если делегат Click объявлен как событие.

Я не думал об этом так. Другой ответ еще более практичен, но спасибо за понимание.

Matthew Scharley 22.09.2008 03:26

Мне кажется, что упаковка public MouseEventHandler InvokableOnlyClik => Click; public event MouseEventHandler Click; должна помочь. Это не позволяет вам добавлять, удалять или переназначать его. (При этом я не пробовал его во время выполнения, но он компилировался)

jeromej 03.02.2020 11:21

Вы можете значительно сократить код, предложенный в принятом ответе, используя современный синтаксис .NET framework:

public event Action<int> RecipeSelected;
public void RaiseRecpeSelected(int recipe) => RecipeSelected?.Invoke(recipe);

Другие вопросы по теме