Compartilhar via


Gerar e consumir eventos

Este artigo mostra como trabalhar com eventos no .NET usando o EventHandler delegado, o EventHandler<TEventArgs> delegado e um delegado personalizado, com exemplos de eventos com e sem dados.

Pré-requisitos

Familiarize-se com os conceitos no artigo Eventos .

Gerar um evento sem dados

Essas etapas criam uma Counter classe que aciona um ThresholdReached evento quando um total em execução atinge ou excede um limite.

  1. Declare o evento usando o EventHandler delegate.

    Use EventHandler quando o evento não passar dados para o manipulador:

    public event EventHandler? ThresholdReached;
    
    Public Event ThresholdReached As EventHandler
    
  2. Adicione um protected virtual método (Protected Overridable no Visual Basic) para gerar o evento.

    Esse padrão permite que classes derivadas substituam o comportamento de disparo de eventos sem a necessidade de invocar diretamente o delegado. No C#, use o operador condicional nulo (?.) para se proteger contra nenhum assinante (no Visual Basic, RaiseEvent lida com isso automaticamente):

    protected virtual void OnThresholdReached(EventArgs e)
    {
        ThresholdReached?.Invoke(this, e);
    }
    
    Protected Overridable Sub OnThresholdReached(e As EventArgs)
        RaiseEvent ThresholdReached(Me, e)
    End Sub
    
  3. Chame o método raise quando a condição for atendida.

    Passe Empty porque esse evento não carrega dados:

    if (_total >= _threshold)
    {
        OnThresholdReached(EventArgs.Empty);
    }
    
    If (_total >= _threshold) Then
        OnThresholdReached(EventArgs.Empty)
    End If
    
  4. Assine o evento usando o += operador (no Visual Basic, AddHandler):

    c.ThresholdReached += c_ThresholdReached;
    
    AddHandler c.ThresholdReached, AddressOf c_ThresholdReached
    
  5. Defina o método do manipulador de eventos.

    Sua assinatura deve corresponder ao EventHandler delegado, o primeiro parâmetro é a origem do evento e o segundo é EventArgs:

    static void c_ThresholdReached(object? sender, EventArgs e)
    {
        Console.WriteLine("The threshold was reached.");
        Environment.Exit(0);
    }
    
    Sub c_ThresholdReached(sender As Object, e As EventArgs)
        Console.WriteLine("The threshold was reached.")
        Environment.Exit(0)
    End Sub
    

O exemplo a seguir mostra a implementação completa:

class EventNoData
{
    static void Main()
    {
        Counter c = new(new Random().Next(10));
        c.ThresholdReached += c_ThresholdReached;

        Console.WriteLine("press 'a' key to increase total");
        while (Console.ReadKey(true).KeyChar == 'a')
        {
            Console.WriteLine("adding one");
            c.Add(1);
        }
    }

    static void c_ThresholdReached(object? sender, EventArgs e)
    {
        Console.WriteLine("The threshold was reached.");
        Environment.Exit(0);
    }
}

class Counter(int passedThreshold)
{
    private readonly int _threshold = passedThreshold;
    private int _total;

    public void Add(int x)
    {
        _total += x;
        if (_total >= _threshold)
        {
            OnThresholdReached(EventArgs.Empty);
        }
    }

    protected virtual void OnThresholdReached(EventArgs e)
    {
        ThresholdReached?.Invoke(this, e);
    }

    public event EventHandler? ThresholdReached;
}
Module EventNoData

    Sub Main()
        Dim c As New Counter(New Random().Next(10))
        AddHandler c.ThresholdReached, AddressOf c_ThresholdReached

        Console.WriteLine("press 'a' key to increase total")
        While Console.ReadKey(True).KeyChar = "a"
            Console.WriteLine("adding one")
            c.Add(1)
        End While
    End Sub

    Sub c_ThresholdReached(sender As Object, e As EventArgs)
        Console.WriteLine("The threshold was reached.")
        Environment.Exit(0)
    End Sub
End Module

Class Counter
    Private ReadOnly _threshold As Integer
    Private _total As Integer

    Public Sub New(passedThreshold As Integer)
        _threshold = passedThreshold
    End Sub

    Public Sub Add(x As Integer)
        _total += x
        If (_total >= _threshold) Then
            OnThresholdReached(EventArgs.Empty)
        End If
    End Sub

    Protected Overridable Sub OnThresholdReached(e As EventArgs)
        RaiseEvent ThresholdReached(Me, e)
    End Sub

    Public Event ThresholdReached As EventHandler
End Class

Gerar um evento com dados

Essas etapas estendem o exemplo anterior Counter para gerar um evento que inclui dados, o valor limite e a hora em que ele foi atingido.

  1. Definir uma classe de dados de evento que herda de EventArgs.

    Adicione propriedades para cada parte dos dados que você deseja passar para o manipulador:

    public class ThresholdReachedEventArgs : EventArgs
    {
        public int Threshold { get; set; }
        public DateTime TimeReached { get; set; }
    }
    
    Class ThresholdReachedEventArgs
        Inherits EventArgs
    
        Public Property Threshold As Integer
        Public Property TimeReached As Date
    End Class
    
  2. Declare o evento usando o EventHandler<TEventArgs> delegate, passando sua classe de dados de evento como o argumento de tipo.

    public event EventHandler<ThresholdReachedEventArgs>? ThresholdReached;
    
    Public Event ThresholdReached As EventHandler(Of ThresholdReachedEventArgs)
    
  3. Adicione um protected virtual método (Protected Overridable no Visual Basic) para gerar o evento.

    Esse padrão permite que classes derivadas substituam o comportamento de disparo de eventos sem invocar diretamente o delegado. No C#, use o operador condicional nulo (?.) para se proteger contra nenhum assinante (no Visual Basic, RaiseEvent lida com isso automaticamente):

    protected virtual void OnThresholdReached(ThresholdReachedEventArgs e)
    {
        ThresholdReached?.Invoke(this, e);
    }
    
    Protected Overridable Sub OnThresholdReached(e As ThresholdReachedEventArgs)
        RaiseEvent ThresholdReached(Me, e)
    End Sub
    
  4. Preencha o objeto de dados de evento e chame o método raise quando a condição for atendida:

    if (_total >= _threshold)
    {
        ThresholdReachedEventArgs args = new ThresholdReachedEventArgs();
        args.Threshold = _threshold;
        args.TimeReached = DateTime.Now;
        OnThresholdReached(args);
    }
    
    If (_total >= _threshold) Then
        Dim args As New ThresholdReachedEventArgs With {
            .Threshold = _threshold,
            .TimeReached = Date.Now
        }
        OnThresholdReached(args)
    End If
    
  5. Assine o evento usando o += operador (no Visual Basic, AddHandler):

    c.ThresholdReached += c_ThresholdReached;
    
    AddHandler c.ThresholdReached, AddressOf c_ThresholdReached
    
  6. Defina o manipulador de eventos.

    O segundo tipo de parâmetro é ThresholdReachedEventArgs , em vez de EventArgs, o que permite que o manipulador leia os dados do evento:

    static void c_ThresholdReached(object? sender, ThresholdReachedEventArgs e)
    {
        Console.WriteLine($"The threshold of {e.Threshold} was reached at {e.TimeReached}.");
        Environment.Exit(0);
    }
    
    Sub c_ThresholdReached(sender As Object, e As ThresholdReachedEventArgs)
        Console.WriteLine("The threshold of {0} was reached at {1}.", e.Threshold, e.TimeReached)
        Environment.Exit(0)
    End Sub
    

O exemplo a seguir mostra a implementação completa:

class EventWithData
{
    static void Main()
    {
        CounterWithData c = new(new Random().Next(10));
        c.ThresholdReached += c_ThresholdReached;

        Console.WriteLine("press 'a' key to increase total");
        while (Console.ReadKey(true).KeyChar == 'a')
        {
            Console.WriteLine("adding one");
            c.Add(1);
        }
    }

    static void c_ThresholdReached(object? sender, ThresholdReachedEventArgs e)
    {
        Console.WriteLine($"The threshold of {e.Threshold} was reached at {e.TimeReached}.");
        Environment.Exit(0);
    }
}

class CounterWithData(int passedThreshold)
{
    private readonly int _threshold = passedThreshold;
    private int _total;

    public void Add(int x)
    {
        _total += x;
        if (_total >= _threshold)
        {
            ThresholdReachedEventArgs args = new ThresholdReachedEventArgs();
            args.Threshold = _threshold;
            args.TimeReached = DateTime.Now;
            OnThresholdReached(args);
        }
    }

    protected virtual void OnThresholdReached(ThresholdReachedEventArgs e)
    {
        ThresholdReached?.Invoke(this, e);
    }

    public event EventHandler<ThresholdReachedEventArgs>? ThresholdReached;
}

public class ThresholdReachedEventArgs : EventArgs
{
    public int Threshold { get; set; }
    public DateTime TimeReached { get; set; }
}
Module EventWithData

    Sub Main()
        Dim c As New CounterWithData(New Random().Next(10))
        AddHandler c.ThresholdReached, AddressOf c_ThresholdReached

        Console.WriteLine("press 'a' key to increase total")
        While Console.ReadKey(True).KeyChar = "a"
            Console.WriteLine("adding one")
            c.Add(1)
        End While
    End Sub

    Sub c_ThresholdReached(sender As Object, e As ThresholdReachedEventArgs)
        Console.WriteLine("The threshold of {0} was reached at {1}.", e.Threshold, e.TimeReached)
        Environment.Exit(0)
    End Sub
End Module

Class CounterWithData
    Private ReadOnly _threshold As Integer
    Private _total As Integer

    Public Sub New(passedThreshold As Integer)
        _threshold = passedThreshold
    End Sub

    Public Sub Add(x As Integer)
        _total += x
        If (_total >= _threshold) Then
            Dim args As New ThresholdReachedEventArgs With {
                .Threshold = _threshold,
                .TimeReached = Date.Now
            }
            OnThresholdReached(args)
        End If
    End Sub

    Protected Overridable Sub OnThresholdReached(e As ThresholdReachedEventArgs)
        RaiseEvent ThresholdReached(Me, e)
    End Sub

    Public Event ThresholdReached As EventHandler(Of ThresholdReachedEventArgs)
End Class

Class ThresholdReachedEventArgs
    Inherits EventArgs

    Public Property Threshold As Integer
    Public Property TimeReached As Date
End Class

Declarar um delegado personalizado para um evento

Declare um delegado personalizado apenas em cenários raros, como disponibilizar sua classe para código herdado que não pode usar genéricos. Para a maioria dos casos, use EventHandler<TEventArgs> conforme mostrado na seção anterior.

  1. Declare o tipo de delegado personalizado.

    A assinatura do delegado deve corresponder à assinatura do manipulador de eventos — dois parâmetros: a origem do evento (object; no Visual Basic Object) e a classe de dados do evento:

    public delegate void ThresholdReachedEventHandler(object sender, ThresholdReachedEventArgs e);
    
    Delegate Sub ThresholdReachedEventHandler(sender As Object, e As ThresholdReachedEventArgs)
    
  2. Declare o evento usando o tipo de delegado personalizado em vez de EventHandler<TEventArgs>:

    public event ThresholdReachedEventHandler? ThresholdReached;
    
    Public Event ThresholdReached As ThresholdReachedEventHandler
    
  3. Adicione um protected virtual método (Protected Overridable no Visual Basic) para gerar o evento.

    No C#, use o operador condicional nulo (?.) para se proteger contra nenhum assinante (no Visual Basic, RaiseEvent lida com isso automaticamente):

    protected virtual void OnThresholdReached(ThresholdReachedEventArgs e)
    {
        ThresholdReached?.Invoke(this, e);
    }
    
    Protected Overridable Sub OnThresholdReached(e As ThresholdReachedEventArgs)
        RaiseEvent ThresholdReached(Me, e)
    End Sub
    
  4. Preencha o objeto de dados de evento e chame o método raise quando a condição for atendida:

    if (_total >= _threshold)
    {
        ThresholdReachedEventArgs args = new();
        args.Threshold = _threshold;
        args.TimeReached = DateTime.Now;
        OnThresholdReached(args);
    }
    
    If (_total >= _threshold) Then
        Dim args As New ThresholdReachedEventArgs With {
            .Threshold = _threshold,
            .TimeReached = Date.Now
        }
        OnThresholdReached(args)
    End If
    
  5. Assine o evento usando o += operador (no Visual Basic, AddHandler):

    c.ThresholdReached += c_ThresholdReached;
    
    AddHandler c.ThresholdReached, AddressOf c_ThresholdReached
    
  6. Defina o manipulador de eventos.

    A assinatura do manipulador para o remetente deve corresponder ao delegado personalizado—object—e sua classe de dados de evento para o segundo parâmetro.

    static void c_ThresholdReached(object sender, ThresholdReachedEventArgs e)
    {
        Console.WriteLine($"The threshold of {e.Threshold} was reached at {e.TimeReached}.");
        Environment.Exit(0);
    }
    
    Sub c_ThresholdReached(sender As Object, e As ThresholdReachedEventArgs)
        Console.WriteLine("The threshold of {0} was reached at {1}.", e.Threshold, e.TimeReached)
        Environment.Exit(0)
    End Sub
    

O exemplo a seguir mostra a implementação completa:

class EventWithDelegate
{
    static void Main()
    {
        CounterWithDelegate c = new(new Random().Next(10));
        c.ThresholdReached += c_ThresholdReached;

        Console.WriteLine("press 'a' key to increase total");
        while (Console.ReadKey(true).KeyChar == 'a')
        {
            Console.WriteLine("adding one");
            c.Add(1);
        }
    }

    static void c_ThresholdReached(object sender, ThresholdReachedEventArgs e)
    {
        Console.WriteLine($"The threshold of {e.Threshold} was reached at {e.TimeReached}.");
        Environment.Exit(0);
    }
}

class CounterWithDelegate(int passedThreshold)
{
    private readonly int _threshold = passedThreshold;
    private int _total;

    public void Add(int x)
    {
        _total += x;
        if (_total >= _threshold)
        {
            ThresholdReachedEventArgs args = new();
            args.Threshold = _threshold;
            args.TimeReached = DateTime.Now;
            OnThresholdReached(args);
        }
    }

    protected virtual void OnThresholdReached(ThresholdReachedEventArgs e)
    {
        ThresholdReached?.Invoke(this, e);
    }

    public event ThresholdReachedEventHandler? ThresholdReached;
}

public delegate void ThresholdReachedEventHandler(object sender, ThresholdReachedEventArgs e);
Module EventWithDelegate

    Sub Main()
        Dim c As New CounterWithDelegate(New Random().Next(10))
        AddHandler c.ThresholdReached, AddressOf c_ThresholdReached

        Console.WriteLine("press 'a' key to increase total")
        While Console.ReadKey(True).KeyChar = "a"
            Console.WriteLine("adding one")
            c.Add(1)
        End While
    End Sub

    Sub c_ThresholdReached(sender As Object, e As ThresholdReachedEventArgs)
        Console.WriteLine("The threshold of {0} was reached at {1}.", e.Threshold, e.TimeReached)
        Environment.Exit(0)
    End Sub
End Module

Class CounterWithDelegate
    Private ReadOnly _threshold As Integer
    Private _total As Integer

    Public Sub New(passedThreshold As Integer)
        _threshold = passedThreshold
    End Sub

    Public Sub Add(x As Integer)
        _total += x
        If (_total >= _threshold) Then
            Dim args As New ThresholdReachedEventArgs With {
                .Threshold = _threshold,
                .TimeReached = Date.Now
            }
            OnThresholdReached(args)
        End If
    End Sub

    Protected Overridable Sub OnThresholdReached(e As ThresholdReachedEventArgs)
        RaiseEvent ThresholdReached(Me, e)
    End Sub

    Public Event ThresholdReached As ThresholdReachedEventHandler
End Class

Delegate Sub ThresholdReachedEventHandler(sender As Object, e As ThresholdReachedEventArgs)