English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Evento (Event) do C#

C# Orientado a Objetos (OOP)

Os eventos são notificações enviadas por objetos para representar a ocorrência de uma operação. Os eventos no .NET seguem o padrão de design Observer. A classe que dispara o evento é chamada

Publisher (publicador), a classe que recebe notificações é chamada Subscriber (assinante). Um evento pode ter múltiplos assinantes. Normalmente, o publisher dispara um evento quando uma operação ocorre. Os assinantes desejam ser notificados quando uma operação ocorre, então eles devem se registrar no evento e tratá-lo.

Em C#, os eventos são encapsulados em delegações. Dependem da delegação. A delegação define a assinatura do método do tratador de eventos da classe subscriber.

A ilustração a seguir mostra eventos no C#.

Publisher e subscriber de eventos

Uso de eventos com delegações publisher Classe. Outras classes que aceitam este evento são chamadas de classes subscriber(subscriber). Os eventos são declarados e gerados dentro da classe e associados a tratadores de eventos usando delegações da mesma classe ou de outras classes. A classe que contém eventos é usada para publicar eventos. Isso é chamado de Publicar-Assinar(publisher-subscriber) Modelo.

publisher- É um objeto que contém definições de eventos e delegações. A relação entre eventos e delegações também é definida neste objeto. O objeto da classe publisher chama este evento e notifica outros objetos.

Assinante(subscriber)- É um objeto que aceita eventos e fornece métodos de tratamento de eventos. A chamada de delegado no classe publisher chama o método da classe subscriber (método de tratamento de evento).

Declarar o evento

Pode-se declarar um evento em dois passos:

  1. Declarar o delegado

  2. Declarar uma variável de delegado usando a palavra-chave 'event'

O exemplo a seguir demonstra como declarar um evento no classe publisher.

public delegate void Notify();  // Delegado
                    
public class ProcessBusinessLogic
{
    public event Notify ProcessCompleted; // Evento
}

No exemplo acima, declaramos um delegado Notify e, em seguida, usamos a palavra-chave 'event' para declarar o evento do tipo de delegado Notify chamado ProcessCompleted no classe ProcessBusinessLogic. Portanto, a classe ProcessBusinessLogic é chamada de publisher (publicador). O delegado Notify especifica a assinatura do tratamento de eventos do evento ProcessCompleted. Ele especifica que o método do tratamento de eventos da classe subscriber (assinante) deve ter o tipo de retorno void e não ter parâmetros.

Agora, vamos ver como provocar o evento ProcessCompleted. Veja a seguinte implementação.

public delegate void Notify();  // Delegado
                    
public class ProcessBusinessLogic
{
    public event Notify ProcessCompleted; // Evento
    public void StartProcess()
    {
        Console.WriteLine("Processo iniciado!");
        // Alguns código aqui...
        OnProcessCompleted();
    }
    protected virtual void OnProcessCompleted() //Método virtual protegido
    {
        //Se ProcessCompleted não for null, chama o delegado
        ProcessCompleted?.Invoke(); 
    }
}

Acima, o método StartProcess() chama o método onProcessCompleted() no final, o que provocará um evento. Normalmente, para provocar um evento, deve-se usar o nome definido no <EventName> para o método protegido e virtual. Protegido e virtual permitem que a classe derivada sobrescreva a lógica de provocação de eventos. No entanto, a classe derivada deve sempre chamar o método On<EventName> da classe base para garantir que os delegados registrados recebam o evento.

O método OnProcessCompleted() utiliza ProcessCompleted?.invoke() para chamar o delegado. Isso chamará todos os métodos de tratamento de eventos registrados no evento ProcessCompleted.

A classe assinante deve se registrar no evento ProcessCompleted e usar um método com assinatura correspondente ao delegate Notify para tratá-lo, conforme mostrado a seguir.

class Program
{
    public static void Main()
    {
        ProcessBusinessLogic bl = new ProcessBusinessLogic();
        bl.ProcessCompleted += bl_ProcessCompleted; // Registrar eventos
        bl.StartProcess();
    }
    // Manipulador de eventos
    public static void bl_ProcessCompleted()
    {
        Console.WriteLine("Processo Concluído!");
    }
}

Acima, a classe Program é ProcessCompleted Os assinantes do evento. Ele usa + O operador de atribuição = para registrar eventos. Lembre-se de que isso é o mesmo que adicionarmos métodos à lista de chamadas do delegate de multicast. O método bl_processcompleted() lida com o evento porque coincide com a assinatura do delegate Notify.

Delegate EventHandler integrado

.NET Framework contém tipos de delegate integrados para eventos mais comuns, EventHandler e EventHandler<TEventArgs>. Normalmente, qualquer evento deve incluir dois parâmetros: a fonte do evento e os dados do evento. Para todos os eventos que não contêm dados de evento, use o delegate EventHandler. Para eventos que contêm dados a serem enviados para o manipulador, use o delegate EventHandler<TEventArgs>.

O exemplo mostrado pode usar o delegate EventHandler, sem a necessidade de declarar um delegate Notify personalizado, conforme mostrado a seguir.

class Program
{
    public static void Main()
    {
        ProcessBusinessLogic bl = new ProcessBusinessLogic();
        bl.ProcessCompleted += bl_ProcessCompleted; // registo de eventos
        bl.StartProcess();
    }
    // manipulação de eventos
    public static void bl_ProcessCompleted(object sender, EventArgs e)
    {
        Console.WriteLine("Processo Concluído!");
    }
}
public class ProcessBusinessLogic
{
    // Use a declaração de EventHandler incorporado para eventos
    public event EventHandler ProcessCompleted; 
    public void StartProcess()
    {
        Console.WriteLine("Processo iniciado!");
        // Alguns código aqui...
        OnProcessCompleted(EventArgs.Empty); //Nenhum dado de evento
    }
    protected virtual void OnProcessCompleted(EventArgs e)
    {
        ProcessCompleted?.Invoke(this, e);
    }
}

No exemplo acima, o método bl_ProcessCompleted() do manipulador de eventos contém dois parâmetros que correspondem ao delegate EventHandler. Ao mesmo tempo, passa this como o remetente e EventArgs. Quando usamos Invoke() para levantar o evento no método OnProcessCompleted(), ele é vazio. Porque nosso evento não precisa de qualquer dados, ele apenas notifica os assinantes de que o processo já foi concluído, então passamos EventArgs.Empty.

Passar dados do evento

A maioria dos eventos envia alguns dados para os assinantes. A classe EventArgs é a classe base para todas as classes de dados de evento. O .NET contém muitos tipos de dados de evento integrados, como SerialDataReceivedEventArgs. Ele segue o padrão de nomeação de terminar todas as classes de dados de evento com EventArgs. Você pode criar classes personalizadas de dados de evento derivando da classe EventArgs.

Use EventHandler<TEventArgs> para passar dados para o processador, conforme mostrado a seguir.

class Program
{
    public static void Main()
    {
        ProcessBusinessLogic bl = new ProcessBusinessLogic();
        bl.ProcessCompleted += bl_ProcessCompleted; // registo de eventos
        bl.StartProcess();
    }
    // manipulação de eventos
    public static void bl_ProcessCompleted(object sender, bool IsSuccessful)
    {
        Console.WriteLine("Processo " + (IsSuccessful ? "Completed Successfully" : "failed");
    }
}
public class ProcessBusinessLogic
{
    // Use a declaração de EventHandler incorporado para eventos
    public event EventHandler<bool> ProcessCompleted; 
    public void StartProcess()
    {
        try
        {
            Console.WriteLine("Processo iniciado!");
            // Alguns código aqui...
            OnProcessCompleted(true);
        }
        catch(Exception ex)
        {
            OnProcessCompleted(false);
        }
    }
    protected virtual void OnProcessCompleted(bool IsSuccessful)
    {
        ProcessCompleted?.Invoke(this, IsSuccessful);
    }
}

No exemplo acima, passamos um valor booleano único para o processador para indicar se o processo foi concluído com sucesso.

Se desejar passar vários valores como dados do evento, pode criar uma classe derivada da classe base EventArgs, conforme mostrado a seguir.

class ProcessEventArgs : EventArgs
{
    public bool IsSuccessful { get; set; }
    public DateTime CompletionTime { get; set; }
}

O exemplo a seguir demonstra como passar a classe ProcessEventArgs personalizada para o processador.

class Program
{
    public static void Main()
    {
        ProcessBusinessLogic bl = new ProcessBusinessLogic();
        bl.ProcessCompleted += bl_ProcessCompleted; // registo de eventos
        bl.StartProcess();
    }
    // manipulação de eventos
    public static void bl_ProcessCompleted(object sender, ProcessEventArgs e)
    {
        Console.WriteLine("Processo " + (e.IsSuccessful ? "Concluído com sucesso" : "falhou"));
        Console.WriteLine("Tempo de conclusão: " + e.CompletionTime.ToLongDateString());
    }
}
public class ProcessBusinessLogic
{
    // Use a declaração de EventHandler incorporado para eventos
    public event EventHandler<ProcessEventArgs> ProcessCompleted; 
    public void StartProcess()
    {
        var data = new ProcessEventArgs();
        try
        {
            Console.WriteLine("Processo iniciado!");
            // Alguns código aqui...
            
            data.IsSuccessful = true;
            data.CompletionTime = DateTime.Now;
            OnProcessCompleted(data);
        }
        catch(Exception ex)
        {
            data.IsSuccessful = false;
            data.CompletionTime = DateTime.Now;
            OnProcessCompleted(data);
        }
    }
    protected virtual void OnProcessCompleted(ProcessEventArgs e)
    {
        ProcessCompleted?.Invoke(this, e);
    }
}

Portanto, você pode criar, emitir, registrar e manipular eventos em C#.

Ponto a ser lembrado

  1. Os eventos são uma envoltória de delegados. Isso depende do delegado.

  2. Use a palavra-chave "event" juntamente com a variável do tipo de delegado para declarar eventos.

  3. use os delegados incorporadosEventHandler ouEventHandler <TEventArgs> é usado para eventos comuns.

  4. O classe de publicador lança um evento, enquanto a classe de assinante se registra em um evento e fornece um método de manipulação de eventos.

  5. Nomeie o método que dispara o evento com o nome do evento, começando com 'On'.

  6. A assinatura do método do manipulador deve coincidir com a assinatura do delegado.

  7. Use+ O operador = registra eventos. Use -O operador = desregista, não pode usar o operador =.

  8. Use EventHandler <TEventArgs> para passar dados de eventos.

  9. Derive a classe base EventArgs para criar classes de dados de eventos personalizadas.

  10. Os eventos podem ser declarados como estáticos, virtuais, selados e abstratos (static, virtual, sealed, abstract).

  11. A interface pode incluir eventos como membros.

  12. Se houver múltiplos assinantes, o manipulador de eventos será chamado simultaneamente.