Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stumped - bubbling an routedevent up to top window in WPF - how to capture anywhere!

Tags:

c#

wpf

The literature is awful in this regard - all I want to do is bubble an event up from a control that I have defined but created on the fly (hopefully this will not cause issues) from a broker controller class. The control is a PopUp.

public static readonly RoutedEvent weClosed = EventManager.RegisterRoutedEvent("TIMBOO", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(FixedTaskbarNotifier));


    // Provide CLR accessors for the event
    public event RoutedEventHandler TIMBOO
    {
        add { AddHandler(weClosed, value); }
        remove { RemoveHandler(weClosed, value); }
    }

    // This method raises the Tap event
    void RaiseTapEvent()
    {
        RoutedEventArgs newEventArgs = new RoutedEventArgs(weClosed);
        RaiseEvent(newEventArgs);}


    protected override void OnClosed(EventArgs e)
    {
        //TO DO - rearrange current open windows - fire event?
        Log.Instance.Info("Clean up Window");
        RaiseTapEvent(); This is called on close but nothing fires ..
                }

I am hoping to catch the event somewhere - even in my parent window or higher up the visual tree. This has a reference to a controller that holds the list of notification controls -once I know which one was closed, I can reoganise / repaint any others still active via the controller, but how to catch? Thanks!

like image 860
mttumbledown Avatar asked Mar 04 '10 12:03

mttumbledown


2 Answers

I agree, the documentation on bubbling/tunneling on MSDN isn't great at all.

I've found this MSDN magazine article "Understanding Routed Events and Commands In WPF" much better at explaining the bubbling events.

Look for the "Event Routing" section, copy pasted below:

Event Routing

Understanding a little about the logical and visual trees is important because routed events get routed based primarily on the visual tree. Routed events support a RoutingStrategy of Bubble, Tunnel, or Direct.

Bubble is the most common and means that an event will bubble (propagate) up the visual tree from the source element until either it has been handled or it reaches the root element. This allows you to handle an event on an object further up the element hierarchy from the source element. For example, you could attach a Button.Click handler on the enclosing Grid element instead of directly on the button itself. Bubble events just have names that indicate their action (for example, MouseDown).

Tunnel events go in the other direction, starting at the root element and traversing down the element tree until they are handled or reach the source element for the event. This allows upstream elements to intercept the event and handle it before the event reaches the source element. Tunnel events have their names prefixed with Preview by convention (such as PreviewMouseDown).

Direct events behave like normal events in the .NET Framework. The only potential handler for the event is a delegate that is hooked up to the event.

Usually if a Tunnel event is defined for a particular event, there is a corresponding Bubble event. In that case, the Tunnel event fires first, starting at the root and working its way down to the source element looking for a handler. Once it has been handled or has reached the source element, the Bubble event is fired, working its way up from the source element and looking for a handler. A Bubble or Tunnel event does not stop its routing just because an event handler is called. If you want to stop the bubbling or tunneling process, you mark the event as handled in your event handler using the event arguments you are passed:

private void OnChildElementMouseDown(object sender, MouseButtonEventArgs e) { e.Handled = true; }

Once your handler marks an event as handled, it will not be raised to any more handlers. Well, that is only partially true. In reality, event routing continues behind the scenes, and you can explicitly hook up event handlers in code with an override of the UIElement.AddHandler method that has an additional flag to effectively say, "Call me even if the event has been marked as handled." You specify that flag with a call like the following:

m_SomeChildElement.AddHandler(UIElement.MouseDownEvent, (RoutedEventHandler)OnMouseDownCallMeAlways,true);

The first parameter to AddHandler is the RoutedEvent you want to handle. The second is a delegate to the event-handling method (which will need to have the correct signature for the event's delegate). The third parameter indicates whether you want to be notified even if another handler has marked the event as handled. The element on which you call AddHandler is the one that will be watching for the event to flow by during routing.

Hope this helps.

like image 153
CrimsonX Avatar answered Oct 07 '22 06:10

CrimsonX


On your parent, or wherever you want to handle it, you should simply be able to handle the event by declaring what class it is declared on and the event name. In your case, on your window declaration, do:

<Window ... FixedTaskbarNotifier.TIMBOO="<EventHandlerName>">

This will catch all events bubbled up that have not been canceled (and you can even get those, if you want, although I believe that is not considered a good practice).

As a simple example, create a window and place a button on it. On the window, add a handler for the click operation (which is defined on ButtonBase)

<Window ... ButtonBase.Click="Window_Click">

This will then fire any time any child button is clicked, even inside of child controls and such, unless the event is intentionally canceled.

like image 42
Ben Von Handorf Avatar answered Oct 07 '22 08:10

Ben Von Handorf