Bubbling event is not called - wpf

I am studying WPF. Infollowing the example, there is something I don't understand.
In the example below, tunneling event handlers are called, but I am curious about the reason why all bubbling event handlers are not called.
<ScrollViewer PreviewMouseWheel="ScrollViewer_PreviewMouseWheel" <!-- called -->
MouseWheel="ScrollViewer_MouseWheel"> <!-- not called -->
<StackPanel>
<ListBox
PreviewMouseWheel="ListBox_PreviewMouseWheel" <!-- called -->
MouseWheel="ListBox_MouseWheel" <!-- not called -->
VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingStackPanel.VirtualizationMode="Recycling"/>
</StackPanel>
</ScrollViewer>
Thank you.

A ListBox contains a ScrollViewer that handles the MouseWheel event in order to scroll its content by setting e.Handled = true in the corresponding event args. Event handlers up the chain are not called then. This also applies to other variants of items controls that feature a scroll viewer like ListView or DataGrid.
When you set the value of the Handled property to true in the event data for a routed event, this is referred to as "marking the event handled".
[...] handlers added in XAML or the common signature of AddHandler are not invoked in response to a routed event where the event data is already marked handled.
However, at least when adding routed event handlers in code, you can also use handled events.
You must go through the extra effort of adding a handler with the handledEventsToo parameter version (AddHandler(RoutedEvent, Delegate, Boolean)) in order to handle routed events that are marked handled by earlier participants in the event route.
For example, you can define an x:Name for your ListView to be able to access it in code-behind.
<ListBox x:Name="MyListBox"
VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingStackPanel.VirtualizationMode="Recycling"/>
Then you can register the event e.g. in the constructor. The last parameter of the AddHandler method is set to true, so that already handled events will still invoke the registered event handler.
MyListBox.AddHandler(MouseWheelEvent, (MouseWheelEventHandler)ListBox_MouseWheel, true);
Alternatively, you can use the PreviewMouseWheel event instead if it fits your requirements.

Related

EventTrigger fails to trigger on IsEnabledChanged

I have a custom control inherited from UserControl that I am enabling/disabling via a binding and trying to use an EventTrigger for IsEnabledChanged to cause a ChangePropertyAction behavior to execute.
<local:StockmarketFilecard x:Name="StockmarketReport2" VerticalAlignment="Bottom" Panel.ZIndex="0" IsEnabled="{Binding DataContext.BankReportEnabled, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}">
<Interactions:Interaction.Triggers>
<Interactions:EventTrigger EventName="IsEnabledChanged">
<Interactions:ChangePropertyAction PropertyName="MaxHeight" Value="100"/>
</Interactions:EventTrigger>
</Interactions:Interaction.Triggers>
</local:StockmarketFilecard>
Interactions uses the http://schemas.microsoft.com/xaml/behaviors namespace.
Problem is that the ChangePropertyAction is not executed despite the control visibly becoming enabled/disabled. I have tested adding a code-behind eventhandler for IsEnabledChanged on the control and it is called as expected. I have also tested triggering on the Loaded event to verify that the action is correct and the control changes as expected.
What am I missing to get the EventTrigger to trigger on IsEnabledChanged?
What am I missing to get the EventTrigger to trigger on IsEnabledChanged?
The fact that the EventTrigger only handles routed events and IsEnabledChanged is not a routed event.
You may either set the MaxHeight property in an event handler in the code-behind of the view, or implement an attached behaviour as suggested here.

Catching right mouse click on user control level

<UserControl>
<Grid>
<!-- multiple controls here -->
</Grid>
</UserControl>
As the above example says, there are multiple MS / 3rd party controls hosted on UserControl. I need to catch mouse right click over the UserControl (or any of its child controls). It seems that PreviewMouseRightButtonUp event is not fired when clicked on some of the 3rd party controls inside the UserControl. As per documentation, PreviewMouseRightButtonUp is not a tunneling event, but a direct event, so it is possible that some 3d party controls do not notify the subscribers about this event.
I have also tried to add handler to this event, but still no result
AddHandler(UserControl.PreviewMouseRightButtonDownEvent, new RoutedEventHandler(GetHandledToo), true);
AddHandler(UserControl.PreviewMouseRightButtonUpEvent, new RoutedEventHandler(GetHandledToo), true);
AddHandler(UserControl.MouseRightButtonDownEvent, new RoutedEventHandler(GetHandledToo), true);
AddHandler(UserControl.MouseRightButtonUpEvent, new RoutedEventHandler(GetHandledToo), true);
So, is there a way to always catch the right mouse button event on the user control level, no matter if it is being marked as handled or not?
Edit: I have found where the problem lies. The problem lies in the ContentControl which has not yet evaluated its content. Example:
<ContentControl x:Name="chart" Content="{Binding DiagramScreen}" />
ContentControl recolves its structure through DataTemplate. If DiagramScreen is NULL, the ContentControl's content is not yet created. This means that the space that this ContentControl occupies in UserControl is not responding to Mouse events. How Can I make ContentControl respond to mouse events, even if its content is NULL?
I think if it is handled you can't get it further for bubbling event. A workaround is to pass your host object to your user control. After that, you can call whatever method you want from your host object. It's ugly but I think it will work

How do I make multiple event bindings with ImpromptuInterface.MVVM?

Binding to a single event with ImpromptuInterface.MVVM is very simple:
<DataGrid MVVM:Event.Bind="{Binding Events.RowEditEnding.To[DoRowEditEnding]}"
...
How do I bind to a second event in the same DataGrid control?
You can always chain another event after the To statement. Here is an example where I've used it to bind multiple mouse listening events from one object:
<Grid Background="{Binding Color}" MVVM:Event.Bind="{Binding Events.MouseEnter.To[CenterMouseEnter].MouseLeave.To[MouseLeave].MouseLeftButtonDown.To[LeftButtonClick]}"

How to listen Binding.SourceUpdated on all children of a root element?

I want to listen Binding.SourceUpdated on all the child bindings defined.
http://msdn.microsoft.com/en-us/library/system.windows.data.binding.sourceupdated.aspx says
Set the NotifyOnTargetUpdated or NotifyOnSourceUpdated property (or both) to true in the binding. The handler you provide to listen for this event must be attached directly to the element where you want to be informed of changes, or to the overall data context if you want to be aware that anything in the context has changed.
That means we should be able to listen those event per DataContext instead of per Binding element.
Like most WPF events, SourceUpdated is a Routed Event. Any event handler for this event placed on a given element will also be called when a child element raises this event.
If you have the following code:
<StackPanel Binding.SourceUpdated="OnBindingSourceUpdated">
<TextBlock Text="{Binding Path=A, NotifyOnSourceUpdated=True}" />
<TextBlock Text="{Binding Path=B, NotifyOnSourceUpdated=True}" />
</StackPanel>
The handler OnBindingSourceUpdated will handle binding source changes for both textboxes. Place the attached event handler on the element where the data context is originally defined and you'll get notifications for every source change.

Silverlight Listbox firing MouseRightButtonDown, but not MouseLeftButtonDown

I have this problem in a bigger Project...... so I set up a 'Testpoject' as Proof of Concept:
New Silverlight-Application
Add Listbox
Fill listbox with a few Checkboxes
Register listBox1_MouseLeftButtonDown
register listBox1_MouseRightButtonDown
You will see, that the listBox1_MouseLeftButtonDown won't fire under any circumstances....
listBox1_MouseRightButtonDown however fires just fine.
I tried using a custom Class deriving from ListBox and overriding, assuming something in the ListBox Class was setting e.Handled = false, but this did not change the behaviour, either.
Any Ideas on why this happens and how to fix?
(This problem also stops the 'parent'-control from receiving the Click-Event... so the Event-passing is broke)
:edit:
I fixed my problem with a workaround... so an answer is not required anymore. Just if somebody feels like figuring out why this is happening for the sake of it ;)
This seems to answer your question. To quote:
That's because ListBoxItem internally handles this event as well as the MouseLeftButtonDown event (halting the bubbling) to implement item selection.
The solution is to add the event handler in the code-behind file. From the article:
Although setting the RoutedEventArgs parameter's Handled property to true in a routed event handler appears to stop the tunneling or bubbling, individual handlers further up or down the tree can opt to receive the events anyway! This can only be done from procedural code, using an overload of AddHandler that adds a Boolean handledEventsToo parameter.
See the caveat at the end though.
This is by design. If you check the framework code, you'll see that the ListBoxItem sets the Handled property to true.
I had this same exact problem, so in my ListBoxItem.ItemTemplate, I added the event handler in my content.
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" MouseLeftButtonDown="StackPanel_MouseLeftButtonDown">
... other controls ...
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>

Resources