Search code examples
c#wpfevents

Sending custom event to WPF window from code-behind


I'm trying to subscribe to a custom event fired from code-behind in an EventTrigger element. All the examples I can find are for events triggered by the front-end, but I want to do it the other way around. Here is some example code, which is intended to trigger the animation every second:

Code behind:

    public partial class MainWindow : Window
    {
        public static readonly RoutedEvent RoutedEvent = EventManager.RegisterRoutedEvent(
               name: "TestRoutedEventName",
               routingStrategy: RoutingStrategy.Bubble,
               handlerType: typeof(RoutedEventHandler),
               ownerType: typeof(MainWindow));

        public event RoutedEventHandler Event
        {
            add { AddHandler(RoutedEvent, value); }
            remove { RemoveHandler(RoutedEvent, value); }
        }

        public MainWindow()
        {
            InitializeComponent();

            _ = new DispatcherTimer(
                TimeSpan.FromSeconds(1000),
                DispatcherPriority.Normal,
                (sender, args) => RaiseEvent(new RoutedEventArgs(RoutedEvent)),
                App.Current.Dispatcher);
        }
    }

XAML:

<Window x:Class="WpfEventTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfEventTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="200" Width="200">
    <StackPanel>
        <Viewbox Stretch="Fill" Width="100" Height="100">
            <Canvas Width="100" Height="100">
                <Path Fill="#FF0000" Name="Path">
                    <Path.Data>
                        <PathGeometry Figures="M 10 10 H 90 V 90 H 10 L 10 10" FillRule="NonZero"/>
                    </Path.Data>
                    <Path.Triggers>
                        <EventTrigger RoutedEvent="**WHAT DO I PUT IN HERE**">
                            <BeginStoryboard>
                                <Storyboard>
                                    <ColorAnimation
                                        Storyboard.TargetName="Path"
                                        Storyboard.TargetProperty="Fill.Color"
                                        From="Red" To="White" Duration="0:0:0.8" />
                                </Storyboard>
                            </BeginStoryboard>
                        </EventTrigger>
                    </Path.Triggers>
                </Path>
            </Canvas>
        </Viewbox>
    </StackPanel>
</Window>

At the moment I'm just using a DispatcherTimer for simplicity, but the event needs to come from an external source.

Questions:

  1. Is something like this possible?
  2. If so, what syntax do I use to bind the RoutedEvent to the EventTrigger?
  3. If not how do I do it?

Solution

  • Your event name doesn't match your event's name.

    For name "TestRoutedEventName" the field should be named public static readonly RoutedEvent TestRoutedEventNameEvent, and event should be named public event RoutedEventHandler TestRoutedEventName.

    Considering that the field will be named TestRoutedEventNameEvent and NS is xmlns:local="clr-namespace:WpfEventTest" you should write in XAML:

    <EventTrigger RoutedEvent="{x:Static local:MainWindow.TestRoutedEventNameEvent}">
        ...
    </EventTrigger>
    

    To make it work you have to trigger the event (call RaiseEvent) on the Path instance. Calling RaiseEvent on the window instance won't work.

    Note: Since it's a bubbling event, calling RaiseEvent on any logical child of Path would also work, but Path can't have any logical children.