АланКэй придумал ООП, и мы смогли разделить код на классы. Еще более умные люди дали возможность простым смертным кодить так, что бы классы могли создаваться и что то делать в разных потоках, но дальше что то пошло не так. Появилась потребность организовать взаимодействие между потоками и тут началось. Зачем-то начали городить огород с делегатами, протоколами и в итоге, что бы передать управление из одного потока в другой начали писать:
public class MyClass
{
public delegate void OnMessageDelegate(string msg);
public event OnMessageDelegate OnMessage;
и только недавно, я заметил, что, видимо с какой-то версии .Net, стало возможно писать в одну строку, вполне понятным синтаксисом:
public class MyClass
{
public event Action OnMessage;
В новых версиях C#, после v.7, компилятор будет предупреждать о том, что переменная OnMessage может быть NULL при выходе из конструктора, поэтому тут надо писать уже так:
public event Action? OnMessage
Если никто из клиентов этого класса не подписан на событие OnMessage, то, конечно, значение переменной будет NULL и при вызове будет возникать исключение NullReference, поэтому вызов надо делать так:
OnMessage?.Invoke("привет");
На форме можно тогда подписаться на это событие
myClass.OnMessage += ShowMessage;
В методе ShowMessage можно отобразить сообщение на контроле формы типа в TextBox, но поскольку сообщение пришло скорее всего из другого потока, иначе зачем его ваще слать, обращение к контролу на форме надо обернуть в такой вот Invoke