I might be wrong in my opinion - but at least I looked some time ago for quite some length into InputManager
.
My resume from that is: The bubbling and tunneling is done by InputManager
. However calling uielement.Raise()
will only ever deliver the event directly (regardless of the RoutingStrategy
as Ray Burns mentioed).
But (guessing) depending on RoutingStrategy
the InputManager
goes up and down the visual tree between CompositionRoot
and the VisualTreeHlper.Hittest()-
ed Visual and delivers tunneling and bublling events.
There is a way to raise Events via the InputManager, but it is not official and needs reflection (I have it from another Stackoverflow post):
void RaiseMouseInputReportEvent(Visual eventSource, int timestamp, int pointX, int pointY, int wheel)
{
Assembly targetAssembly = Assembly.GetAssembly(typeof(InputEventArgs));
Type mouseInputReportType = targetAssembly.GetType("System.Windows.Input.RawMouseInputReport");
Object mouseInputReport = mouseInputReportType.GetConstructors()[0].Invoke(new Object[] {
InputMode.Foreground, timestamp, PresentationSource.FromVisual(eventSource),
RawMouseActions.AbsoluteMove | RawMouseActions.Activate,
pointX, pointY, wheel, IntPtr.Zero });
mouseInputReportType.GetField("_isSynchronize", BindingFlags.NonPublic | BindingFlags.Instance)
.SetValue(mouseInputReport, true);
InputEventArgs inputReportEventArgs = (InputEventArgs)targetAssembly
.GetType("System.Windows.Input.InputReportEventArgs")
.GetConstructors()[0]
.Invoke(new Object[] {
Mouse.PrimaryDevice,
mouseInputReport });
inputReportEventArgs.RoutedEvent = (RoutedEvent)typeof(InputManager)
.GetField("PreviewInputReportEvent", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)
.GetValue(null);
bool handled = InputManager.Current.ProcessInput((InputEventArgs)inputReportEventArgs);
}