Какие стандартные события в C# ты знаешь?

Ответ

В C# события — это реализация шаблона наблюдатель (Observer), построенная на основе делегатов. Стандартные события можно разделить по областям применения:

1. События пользовательского интерфейса (WinForms/WPF):

  • Click, MouseDown, MouseUp, MouseMove — взаимодействие с мышью.
  • KeyDown, KeyUp, KeyPress — обработка нажатий клавиш.
  • TextChanged — изменение текста в TextBox.
  • SelectedIndexChanged — изменение выбора в ComboBox или ListBox.

2. События жизненного цикла объектов:

  • Load, Shown, FormClosing, FormClosed — для окон Windows Forms.
  • Page_Load, Page_Init — в классическом ASP.NET Web Forms.

3. События компонентов .NET:

  • Elapsed — у класса System.Timers.Timer.
  • Changed, Created, Deleted, Renamed — у FileSystemWatcher для отслеживания файловой системы.
  • CollectionChanged — у ObservableCollection<T> для уведомлений об изменении коллекции (используется в WPF привязке данных).

Почему используется шаблон EventHandler? Он стандартизирован и обеспечивает безопасность типов. Второй параметр e наследуется от EventArgs и может содержать дополнительную информацию о событии.

// Пример объявления и вызова собственного события
public class OrderProcessor
{
    // 1. Объявление события с использованием обобщенного делегата EventHandler<T>
    public event EventHandler<OrderProcessedEventArgs> OrderProcessed;

    public void ProcessOrder(Order order)
    {
        // Логика обработки...
        // 2. Вызов события (проверка на null обязательна!)
        OrderProcessed?.Invoke(this, new OrderProcessedEventArgs { OrderId = order.Id, Time = DateTime.Now });
    }
}

// 3. Класс для аргументов события
public class OrderProcessedEventArgs : EventArgs
{
    public int OrderId { get; set; }
    public DateTime Time { get; set; }
}

// 4. Подписка на событие
processor.OrderProcessed += (sender, e) => 
{
    Console.WriteLine($"Order {e.OrderId} processed at {e.Time}");
};

Важно: Всегда используйте ?.Invoke() для потокобезопасного вызова события. Для событий без дополнительных данных используйте стандартный делегат EventHandler.

Ответ 18+ 🔞

А, события в C#! Ну это ж классика, блядь. Смотри, по сути это просто реализация паттерна "наблюдатель", но через делегаты, чтобы всё красиво и типобезопасно было. Ну типа кто-то что-то сделал — крикнул всем, кто подписался: "Эй, я тут событие совершил, делайте что хотите!".

1. События в интерфейсах (WinForms/WPF и прочая хрень):

  • Click, MouseDown, MouseUp, MouseMove — ну это понятно, мышкой тыкаешь, двигаешь.
  • KeyDown, KeyUp, KeyPress — клаву жмёшь, отпускаешь.
  • TextChanged — в текстбоксе букву поменял, сразу событие.
  • SelectedIndexChanged — в выпадающем списке пункт сменил — оп-па, событие.

2. События жизни объектов (родился, пожил, закрылся):

  • Load, Shown, FormClosing, FormClosed — для окошек в винформах. Загрузилось, показалось, закрывается, закрылось.
  • Page_Load, Page_Init — в старом-добром ASP.NET Web Forms, там своя атмосфера.

3. События от всяких компонентов .NET:

  • Elapsed — у таймера System.Timers.Timer. Прошло время — триггернулось.
  • Changed, Created, Deleted, Renamed — у FileSystemWatcher. Следит за файлами, как маньяк, и шпилит событиями, если что-то изменилось.
  • CollectionChanged — у ObservableCollection<T>. Коллекция поменялась (добавили, убрали элемент) — сразу всем подписчикам сигнал. В WPF на этом вся привязка данных и держится, кстати.

А почему везде этот EventHandler? Да чтобы не выдумывать велосипеды, ёпта! Стандартизировали, безопасность типов есть. Второй параметр e — это наследник EventArgs, в нём можно доп. инфу про событие запихнуть.

// Вот смотри, как своё событие наколхозить
public class OrderProcessor
{
    // 1. Объявляем событие. Используем обобщённый делегат EventHandler<T>, это модно.
    public event EventHandler<OrderProcessedEventArgs> OrderProcessed;

    public void ProcessOrder(Order order)
    {
        // Тут какая-то бизнес-логика, заказ обрабатываем...
        // 2. Вызываем событие. Сначала проверяем, есть ли подписчики, чтобы в null не въехать!
        OrderProcessed?.Invoke(this, new OrderProcessedEventArgs { OrderId = order.Id, Time = DateTime.Now });
    }
}

// 3. Класс для аргументов события. Наследуемся от EventArgs — это правило хорошего тона.
public class OrderProcessedEventArgs : EventArgs
{
    public int OrderId { get; set; }
    public DateTime Time { get; set; }
}

// 4. Подписываемся на событие. Можно через лямбду, удобно же.
processor.OrderProcessed += (sender, e) => 
{
    Console.WriteLine($"Заказ {e.OrderId} обработан в {e.Time}");
};

Запомни на века: Всегда вызывай через ?.Invoke(). Это потокобезопасно и от ошибок спасёт, если подписчиков вдруг не окажется. А для событий, где кроме факта "произошло" ничего не надо, используй обычный EventHandler без всяких <T>. Всё, вопрос закрыт.