Возможно ли это при каких-либо обстоятельствах?
Мои текущие обстоятельства таковы:
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. Есть ли у кого-нибудь еще какие-нибудь идеи получше?





Вам действительно следует обернуть код, который вы хотите выполнить извне, в метод. Затем этот метод может делать все, что будет делать ваше событие, и это событие также вместо этого вызовет этот метод.
Вам просто нужно добавить общедоступный метод для вызова события. 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();
}
Я думаю, он может поднять событие не из класса событий?
Вы вызываете PerformClick () вне класса событий.
Нет, это тот стиль, которым я хотел заниматься; т.е. вызов события из-за пределов класса события. Я просто надеялся, что есть способ избежать этого метода. Я полагаю, что я выберу внутреннее решение, которое я опубликовал, эта настраиваемая форма будет в DLL, поэтому внутренний материал будет скрыт.
Я бы выбрал более чистое решение, размещенное здесь, сделав PerformClick внутренним, если вы не хотите, чтобы он отображался. По моим ощущениям при использовании перечисления и метода CallHandler позже их будет труднее читать / поддерживать.
Ключевое слово event в C# изменяет объявление делегата. Это предотвращает прямое назначение делегату (вы можете использовать только + = и - = в событии) и предотвращает вызов делегата извне класса.
Итак, вы можете изменить свой код, чтобы он выглядел так:
public class CustomGUIElement
{
...
public MouseEventHandler Click;
// etc, and so forth.
...
}
Затем вы можете вызвать событие извне класса следующим образом.
myCustomGUIElement.Click(sender,args);
Недостатком является то, что код, использующий класс, может очень легко перезаписать любые зарегистрированные обработчики с помощью такого кода:
myCustomGUIElement.Click = null;
что недопустимо, если делегат Click объявлен как событие.
Я не думал об этом так. Другой ответ еще более практичен, но спасибо за понимание.
Мне кажется, что упаковка public MouseEventHandler InvokableOnlyClik => Click; public event MouseEventHandler Click; должна помочь. Это не позволяет вам добавлять, удалять или переназначать его. (При этом я не пробовал его во время выполнения, но он компилировался)
Вы можете значительно сократить код, предложенный в принятом ответе, используя современный синтаксис .NET framework:
public event Action<int> RecipeSelected;
public void RaiseRecpeSelected(int recipe) => RecipeSelected?.Invoke(recipe);
Это сработает. Плохо, но это сработает. Сохранение списка обратных вызовов - это, по сути, то, что в любом случае делает событие. Зачем тратить силы на то, чтобы заново реализовать то, что уже есть?