Come creare un evento indirizzato personalizzato (WPF .NET)

Gli sviluppatori di applicazioni e gli autori di componenti di Windows Presentation Foundation (WPF) possono creare eventi indirizzati personalizzati per estendere la funzionalità degli eventi CLR (Common Language Runtime). Per informazioni sulle funzionalità degli eventi indirizzati, vedere Perché usare gli eventi indirizzati. Questo articolo illustra le nozioni di base per la creazione di un evento indirizzato personalizzato.

Importante

La documentazione di Desktop Guide per .NET 7 e .NET 6 è in fase di costruzione.

Prerequisiti

L'articolo presuppone una conoscenza di base degli eventi indirizzati e di aver letto panoramica degli eventi indirizzati. Per seguire gli esempi in questo articolo, è utile se si ha familiarità con Extensible Application Markup Language (XAML) e si sa come scrivere applicazioni Windows Presentation Foundation (WPF).

Passaggi dell'evento indirizzato

I passaggi di base per creare un evento indirizzato sono:

  1. Registrare un RoutedEvent oggetto usando il RegisterRoutedEvent metodo .

  2. La chiamata di registrazione restituisce un'istanza RoutedEvent , nota come identificatore di evento indirizzato, che contiene il nome dell'evento registrato, la strategia di routing e altri dettagli dell'evento. Assegnare l'identificatore a un campo statico di sola lettura. Per convenzione:

    • L'identificatore di un evento indirizzato con una strategia di bubbling è denominato <event name>Event. Ad esempio, se il nome dell'evento è Tap , l'identificatore deve essere denominato TapEvent.
    • L'identificatore di un evento indirizzato con una strategia di tunneling è denominato Preview<event name>Event. Ad esempio, se il nome dell'evento è Tap , l'identificatore deve essere denominato PreviewTapEvent.
  3. Definire le funzioni di accesso agli eventi di aggiunta e rimozione di CLR. Senza le funzioni di accesso agli eventi CLR, sarà possibile aggiungere o rimuovere gestori eventi solo tramite chiamate dirette ai UIElement.AddHandler metodi e UIElement.RemoveHandler . Con le funzioni di accesso agli eventi CLR, si ottengono questi meccanismi di assegnazione del gestore eventi:

    • Per Extensible Application Markup Language (XAML), puoi usare la sintassi degli attributi per aggiungere gestori eventi.
    • Per C#, è possibile usare gli += operatori e -= per aggiungere o rimuovere gestori eventi.
    • Per VB, è possibile usare le istruzioni AddHandler e RemoveHandler per aggiungere o rimuovere gestori eventi.
  4. Aggiungere logica personalizzata per attivare l'evento indirizzato. Ad esempio, la logica potrebbe attivare l'evento in base all'input utente e allo stato dell'applicazione.

Esempio

Nell'esempio seguente viene implementata la CustomButton classe in una libreria di controlli personalizzata. Classe CustomButton , che deriva da Button:

  1. Registra un RoutedEvent oggetto denominato ConditionalClick usando il RegisterRoutedEvent metodo e specifica la strategia di bubbling durante la registrazione.
  2. Assegna l'istanza RoutedEvent restituita dalla chiamata di registrazione a un campo di sola lettura statico denominato ConditionalClickEvent.
  3. Definisce le funzioni di accesso agli eventi di aggiunta e rimozione di CLR.
  4. Aggiunge logica personalizzata per generare l'evento indirizzato personalizzato quando CustomButton si fa clic su e viene applicata una condizione esterna. Anche se il codice di esempio genera l'evento ConditionalClick indirizzato dall'interno del metodo virtuale sottoposto OnClick a override, è possibile generare l'evento in qualsiasi modo scelto.
public class CustomButton : Button
{
    // Register a custom routed event using the Bubble routing strategy.
    public static readonly RoutedEvent ConditionalClickEvent = EventManager.RegisterRoutedEvent(
        name: "ConditionalClick",
        routingStrategy: RoutingStrategy.Bubble,
        handlerType: typeof(RoutedEventHandler),
        ownerType: typeof(CustomButton));

    // Provide CLR accessors for assigning an event handler.
    public event RoutedEventHandler ConditionalClick
    {
        add { AddHandler(ConditionalClickEvent, value); }
        remove { RemoveHandler(ConditionalClickEvent, value); }
    }

    void RaiseCustomRoutedEvent()
    {
        // Create a RoutedEventArgs instance.
        RoutedEventArgs routedEventArgs = new(routedEvent: ConditionalClickEvent);

        // Raise the event, which will bubble up through the element tree.
        RaiseEvent(routedEventArgs);
    }

    // For demo purposes, we use the Click event as a trigger.
    protected override void OnClick()
    {
        // Some condition combined with the Click event will trigger the ConditionalClick event.
        if (DateTime.Now > new DateTime())
            RaiseCustomRoutedEvent();

        // Call the base class OnClick() method so Click event subscribers are notified.
        base.OnClick();
    }
}
Public Class CustomButton
    Inherits Button

    ' Register a custom routed event with the Bubble routing strategy.
    Public Shared ReadOnly ConditionalClickEvent As RoutedEvent = EventManager.RegisterRoutedEvent(
        name:="ConditionalClick",
        routingStrategy:=RoutingStrategy.Bubble,
        handlerType:=GetType(RoutedEventHandler),
        ownerType:=GetType(CustomButton))

    ' Provide CLR accessors to support event handler assignment.
    Public Custom Event ConditionalClick As RoutedEventHandler

        AddHandler(value As RoutedEventHandler)
            [AddHandler](ConditionalClickEvent, value)
        End AddHandler

        RemoveHandler(value As RoutedEventHandler)
            [RemoveHandler](ConditionalClickEvent, value)
        End RemoveHandler

        RaiseEvent(sender As Object, e As RoutedEventArgs)
            [RaiseEvent](e)
        End RaiseEvent

    End Event

    Private Sub RaiseCustomRoutedEvent()

        ' Create a RoutedEventArgs instance.
        Dim routedEventArgs As New RoutedEventArgs(routedEvent:=ConditionalClickEvent)

        ' Raise the event, which will bubble up through the element tree.
        [RaiseEvent](routedEventArgs)

    End Sub

    ' For demo purposes, we use the Click event as a trigger.
    Protected Overrides Sub OnClick()

        ' Some condition combined with the Click event will trigger the ConditionalClick event.
        If Date.Now > New DateTime() Then RaiseCustomRoutedEvent()

        ' Call the base class OnClick() method so Click event subscribers are notified.
        MyBase.OnClick()

    End Sub
End Class

L'esempio include un'applicazione WPF separata che usa il markup XAML per aggiungere un'istanza CustomButton di a un StackPaneloggetto e per assegnare il Handler_ConditionalClick metodo come ConditionalClick gestore eventi per gli CustomButton elementi e StackPanel1 .

<Window x:Class="CodeSample.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:custom="clr-namespace:WpfControl;assembly=WpfControlLibrary"
        Title="How to create a custom routed event" Height="100" Width="300">

    <StackPanel Name="StackPanel1" custom:CustomButton.ConditionalClick="Handler_ConditionalClick">
        <custom:CustomButton
            Name="customButton"
            ConditionalClick="Handler_ConditionalClick"
            Content="Click to trigger a custom routed event"
            Background="LightGray">
        </custom:CustomButton>
    </StackPanel>
</Window>

Nel code-behind l'applicazione WPF definisce il metodo del Handler_ConditionalClick gestore eventi. I metodi del gestore eventi possono essere implementati solo nel code-behind.

// The ConditionalClick event handler.
private void Handler_ConditionalClick(object sender, RoutedEventArgs e)
{
    string senderName = ((FrameworkElement)sender).Name;
    string sourceName = ((FrameworkElement)e.Source).Name;

    Debug.WriteLine($"Routed event handler attached to {senderName}, " +
        $"triggered by the ConditionalClick routed event raised on {sourceName}.");
}

// Debug output when CustomButton is clicked:
// Routed event handler attached to CustomButton,
//     triggered by the ConditionalClick routed event raised on CustomButton.
// Routed event handler attached to StackPanel1,
//     triggered by the ConditionalClick routed event raised on CustomButton.
' The ConditionalClick event handler.
Private Sub Handler_ConditionalClick(sender As Object, e As RoutedEventArgs)

    Dim sourceName As String = CType(e.Source, FrameworkElement).Name
    Dim senderName As String = CType(sender, FrameworkElement).Name

    Debug.WriteLine($"Routed event handler attached to {senderName}, " +
        $"triggered by the ConditionalClick routed event raised on {sourceName}.")

End Sub

' Debug output when CustomButton is clicked:
' Routed event handler attached to CustomButton,
'     triggered by the ConditionalClick routed event raised on CustomButton.
' Routed event handler attached to StackPanel1,
'     triggered by the ConditionalClick routed event raised on CustomButton.

Quando CustomButton si fa clic su:

  1. L'evento ConditionalClick indirizzato viene generato su CustomButton.
  2. Viene attivato il Handler_ConditionalClick gestore eventi associato a CustomButton .
  3. L'evento ConditionalClick indirizzato attraversa l'albero degli elementi a StackPanel1.
  4. Viene attivato il Handler_ConditionalClick gestore eventi associato a StackPanel1 .
  5. L'evento ConditionalClick indirizzato continua l'albero degli elementi attivando potenzialmente altri ConditionalClick gestori eventi collegati ad altri elementi attraversati.

Il Handler_ConditionalClick gestore eventi ottiene le informazioni seguenti sull'evento che lo ha attivato:

  • Oggetto sender , ovvero l'elemento a cui è associato il gestore eventi. sender sarà CustomButton la prima volta che viene eseguito il gestore e StackPanel1 la seconda volta.
  • Oggetto RoutedEventArgs.Source , ovvero l'elemento che ha originariamente generato l'evento. In questo esempio, è Source sempre CustomButton.

Nota

Una differenza fondamentale tra un evento indirizzato e un evento CLR consiste nel fatto che un evento indirizzato attraversa l'albero degli elementi, cercando gestori, mentre un evento CLR non attraversa l'albero degli elementi e i gestori possono essere collegati solo all'oggetto di origine che ha generato l'evento. Di conseguenza, un evento sender indirizzato può essere qualsiasi elemento attraversato nell'albero degli elementi.

È possibile creare un evento di tunneling allo stesso modo di un evento di bubbling, ad eccezione della strategia di routing nella chiamata di registrazione eventi a Tunnel. Per altre informazioni sugli eventi di tunneling, vedere Eventi di input WPF.

Vedi anche