Dela via


Så här skapar du en anpassad dirigerad händelse (WPF .NET)

Programutvecklare och komponentförfattare i Windows Presentation Foundation (WPF) kan skapa anpassade routade händelser för att utöka funktionerna i CLR-händelser (Common Language Runtime). Information om funktioner för routade händelser finns i Varför använda routade händelser. Den här artikeln beskriver grunderna för att skapa en anpassad dirigerad händelse.

Förutsättningar

Artikeln förutsätter grundläggande kunskaper om routade händelser och att du har läst Översikt över routade händelser. Om du vill följa exemplen i den här artikeln hjälper det om du är bekant med XAML (Extensible Application Markup Language) och vet hur du skriver WPF-program (Windows Presentation Foundation).

Steg för routad händelse

De grundläggande stegen för att skapa en dirigerad händelse är:

  1. Registrera en RoutedEvent med hjälp av metoden RegisterRoutedEvent.

  2. Registreringsanropet returnerar en RoutedEvent-instans, känd som en dirigerad händelseidentifierare, som innehåller det registrerade händelsenamnet, routningsstrategioch annan händelseinformation. Tilldela identifieraren till ett statiskt skrivskyddat fält. Enligt konvention:

    • Identifieraren för en dirigerad händelse med en bubblande strategi heter <event name>Event. Om händelsenamnet till exempel är Tap ska identifieraren namnges TapEvent.
    • Identifieraren för en dirigerad händelse med en -tunnel-strategi heter Preview<event name>Event. Om händelsenamnet till exempel är Tap ska identifieraren namnges PreviewTapEvent.
  3. Definiera CLR lägga till och ta bort händelseåtkomster. Utan CLR-händelseåtkomster kan du bara lägga till eller ta bort händelsehanterare via direkta anrop till metoderna UIElement.AddHandler och UIElement.RemoveHandler. Med CLR-händelseaccessorer får du tillgång till följande mekanismer för tilldelning av händelsehanterare:

    • För XAML (Extensible Application Markup Language) kan du använda attributsyntax för att lägga till händelsehanterare.
    • För C#kan du använda operatorerna += och -= för att lägga till eller ta bort händelsehanterare.
    • För VB kan du använda instruktionen AddHandler och RemoveHandler för att lägga till eller ta bort händelsehanterare.
  4. Lägg till anpassad logik för att utlösa den dirigerade händelsen. Din logik kan till exempel utlösa händelsen baserat på användarindata och programtillstånd.

Exempel

I följande exempel implementeras klassen CustomButton i ett anpassat kontrollbibliotek. Klassen CustomButton, som härleds från Button:

  1. Registrerar en RoutedEvent med namnet ConditionalClick med hjälp av metoden RegisterRoutedEvent och anger strategin för bubblande vid registreringen.
  2. Tilldelar instansen RoutedEvent, som returneras från registreringsanropet, till ett statiskt konstantfält med namnet ConditionalClickEvent.
  3. Definierar CLR lägga till och ta bort händelseåtkomster.
  4. Lägger till anpassad logik för att utlösa den anpassade dirigerade händelsen när CustomButton klickas och ett externt villkor gäller. Även om exempelkoden genererar den ConditionalClick dirigerade händelsen från den åsidosatta OnClick virtuella metoden, kan du utlösa händelsen på det sätt du vill.
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

Exemplet innehåller ett separat WPF-program som använder XAML-markering för att lägga till en instans av CustomButton till en StackPaneloch för att tilldela metoden Handler_ConditionalClick som ConditionalClick händelsehanterare för elementen CustomButton och 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>

I code-behind definierar WPF-programmet den Handler_ConditionalClick händelsehanterarmetoden. Händelsehanterarmetoder kan bara implementeras i 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.

När CustomButton klickas:

  1. Den ConditionalClick dirigerade händelsen aktiveras på CustomButton.
  2. Den Handler_ConditionalClick händelsehanterare som är kopplad till CustomButton utlöses.
  3. Den dirigerade händelsen ConditionalClick går upp i elementträdet till StackPanel1.
  4. Den Handler_ConditionalClick händelsehanterare som är kopplad till StackPanel1 utlöses.
  5. Den ConditionalClick routade händelsen fortsätter upp i elementträdet och utlöser potentiellt andra ConditionalClick händelsehanterare som är kopplade till andra genomgångna element.

Händelsehanteraren för Handler_ConditionalClick hämtar följande information om händelsen som utlöste den:

  • Objektet avsändare, vilket är elementet som händelsehanteraren är kopplad till. sender kommer att vara CustomButton första gången hanteraren körs, och StackPanel1 andra gången.
  • RoutedEventArgs.Source-objektet, vilket är det element som ursprungligen skapade händelsen. I det här exemplet är Source alltid CustomButton.

Notis

En viktig skillnad mellan en dirigerad händelse och en CLR-händelse är att en dirigerad händelse passerar elementträdet och letar efter hanterare, medan en CLR-händelse inte passerar elementträdet och hanterare bara kan ansluta till källobjektet som skapade händelsen. Det innebär att en dirigerad händelse sender kan vara vilket som helst genomgånget element i elementträdet.

Du kan skapa en tunnelhändelse på samma sätt som en bubblande händelse, förutom att du anger routningsstrategin i händelseregistreringsanropet till Tunnel. Mer information om tunnelhändelser finns i WPF-indatahändelser.

Se även