In this earlier blog, I explained how you can create and use a Command to carry out a task based on a variety of user actions. These actions included key presses, mouse actions and key/mouse combinations, as well as clicking on WPF controls. At the time I said that if you didn't want to have the Image move unless the right mouse button was clicked directly on the Image itself (as opposed to clicking anywhere in the Window or on its other children) then you could use Bubbling and Tunneling. When I came to test this theory, however, I couldn't find an obvious way of achieving this. I could stop a right click on the Image working, but that was the exact opposite of what I was trying to do!
Whether this failure is due to the way the Command infrastructure works or (more likely) my inability to grasp the finer nuances of routing, I've had to admit defeat - at least temporarily. So I thought I should at least post up a workaround for anyone who read that blog item and did want the right click to work only on the Image itself.
The 'fix', such as it is, is to ditch the InputGesture for MouseAction.RightClick in the InputGestureCollection and use a standard event handler purely for the Image MouseDown event.
So, the MoveItCommand code becomes:
Public Class MoveItCommand2
Private Shared _moveit As RoutedUICommand
Public Shared ReadOnly Property MoveIt() As RoutedUICommand
Get
Return _moveit
End Get
End Property
Shared Sub New()
' Add keyboard and mouse gestures
Dim UserInputs As New InputGestureCollection()
UserInputs.Add(New KeyGesture(Key.M, ModifierKeys.Alt))
UserInputs.Add(New KeyGesture(Key.F12, ModifierKeys.None))
' UserInputs.Add(New MouseGesture(MouseAction.RightClick, ModifierKeys.None))
UserInputs.Add(New MouseGesture(MouseAction.LeftClick, ModifierKeys.Shift))
' Assign these gestures to the _moveit field (and thereby to the MoveIt property)
_moveit = New RoutedUICommand("Move Element", "Move", GetType(MoveItCommand), UserInputs)
End Sub
End Class
You'll notice that I've renamed the class to MoveItCommand2.
The code behind for the Window now takes an event handler for the Image MouseDown:
Private Sub MoveableImage_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Input.MouseButtonEventArgs) Handles MoveableImage.MouseDown
If e.ChangedButton = MouseButton.Right Then
CommandBinding_Executed(MoveableImage, Nothing)
End If
End Sub
The code in that event handler simply calls the execution code for the original Command (so at least we retain some semblance of coordination).
Finally, the markup for the Image in the XAML Pane includes a pointer to the new MouseDown event handler:
<Image x:Name="MoveableImage" Width="55" Source="questionmark2.jpg"
Canvas.Left="0" Canvas.Top="0"
MouseDown="MoveableImage_MouseDown"
/>
To avoid confusion, I'll show all the revised markup below, as all references to the Command now have '2' appended to them, and they are easy to miss!
<Window x:Class="Window4"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:GetValue"
Title="Right Mouse Test" Height="300" Width="300">
<Window.CommandBindings>
<CommandBinding Command="local:MoveItCommand2.MoveIt"
Executed="CommandBinding_Executed"
CanExecute="CommandBinding_CanExecute"/>
</Window.CommandBindings>
<Grid x:Name="MainGrid">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="218*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- Canvas in the main middle section -->
<Canvas x:Name="MainCanvas" Grid.Row="1"
>
<Image x:Name="MoveableImage" Width="55"
Source="questionmark2.jpg"
Canvas.Left="0" Canvas.Top="0"
MouseDown="MoveableImage_MouseDown" />
</Canvas>
<!-- Menu at the top -->
<Menu Grid.Row="0" Margin="3">
<MenuItem Header="Move It" Margin="5"
Command="local:MoveItCommand2.MoveIt" />
</Menu>
<ToolBar Grid.Row="2" >
<Button Content="Move It"
Command="local:MoveItCommand2.MoveIt" />
</ToolBar>
<Button Grid.Row="1" VerticalAlignment="Bottom"
HorizontalAlignment="Right" Width="100"
Height="33" Content="Move It" Margin="0,0,4,2"
Command="local:MoveItCommand2.MoveIt" />
</Grid>
</Window>