我正在尝试通过鼠标滚轮/触摸板启用侧面滚动,并启用此功能,我已经从此stack overflow answer修改了代码。
这很好。
但是,当我尝试将RoutedEventHandler
换成特定于我在类中使用的事件的自定义处理程序时,我得到了InvalidCastException
。当代码尝试引发事件element.RaiseEvent(ev);
时,将引发此错误。
引发的异常如下。
Exception thrown: 'System.InvalidCastException' in PresentationCore.dll
An unhandled exception of type 'System.InvalidCastException' occurred in PresentationCore.dll
Unable to cast object of type 'SideScrollViewer.MouseHorizontalWheelEventHandler' to type 'System.Windows.Input.MouseEventHandler'.
如何解决?任何帮助或指针都表示赞赏
XAML实施
<Window x:Class="SideScrollViewer.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:SideScrollViewer"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<local:ScrollViewerSide HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<Button Content="Hello" Width="1000" Height="1000"/>
</local:ScrollViewerSide>
</Grid>
</Window>
启用侧面滚动的C#代码
using System;
using System.Collections.Generic;
using System.Security;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interop;
namespace SideScrollViewer
{
public class ScrollViewerSide : ScrollViewer
{
#region Constructor
static ScrollViewerSide()
{
RegisterNewEvents();
DefaultStyleKeyProperty.OverrideMetadata(typeof(ScrollViewerSide), new FrameworkPropertyMetadata(typeof(ScrollViewerSide)));
}
public ScrollViewerSide()
{
Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
Window win = Window.GetWindow(this);
if (win != null)
{
EnableMouseHorizontalWheelSupport(win);
}
}
#endregion
#region Default Values
private const double HORIZONTAL_SCROLL_OFFSET = 48;
#endregion
#region RoutedEvents
public static readonly RoutedEvent PreviewMouseHorizontalWheelEvent =
EventManager.RegisterRoutedEvent("PreviewMouseHorizontalWheel", RoutingStrategy.Tunnel, typeof(MouseHorizontalWheelEventHandler), typeof(ScrollViewerSide));
public static readonly RoutedEvent MouseHorizontalWheelEvent =
EventManager.RegisterRoutedEvent("MouseHorizontalWheel", RoutingStrategy.Bubble, typeof(MouseHorizontalWheelEventHandler), typeof(ScrollViewerSide));
#endregion
#region Events
public event MouseHorizontalWheelEventHandler PreviewMouseHorizontalWheel {
add => AddHandler(PreviewMouseHorizontalWheelEvent, value);
remove => RemoveHandler(PreviewMouseHorizontalWheelEvent, value);
}
public event MouseHorizontalWheelEventHandler MouseHorizontalWheel {
add => AddHandler(MouseHorizontalWheelEvent, value);
remove => RemoveHandler(MouseHorizontalWheelEvent, value);
}
#endregion
#region Class handling methods for scroll events
[SecurityCritical]
[SecuritySafeCritical]
private static void RegisterNewEvents()
{
EventManager.RegisterClassHandler(typeof(ScrollViewerSide), PreviewMouseHorizontalWheelEvent, new MouseHorizontalWheelEventHandler(OnPreviewMouseHorizontalWheelThunk), false);
EventManager.RegisterClassHandler(typeof(ScrollViewerSide), MouseHorizontalWheelEvent, new MouseHorizontalWheelEventHandler(OnMouseHorizontalWheelThunk), false);
}
[SecurityCritical]
private static void OnPreviewMouseHorizontalWheelThunk(object sender, MouseHorizontalWheelEventArgs e)
{
if (!e.Handled && sender is ScrollViewerSide view)
{
view.OnPreviewMouseHorizontalWheel(e);
}
}
protected virtual void OnPreviewMouseHorizontalWheel(MouseHorizontalWheelEventArgs e) { }
[SecurityCritical]
private static void OnMouseHorizontalWheelThunk(object sender, MouseHorizontalWheelEventArgs e)
{
if (!e.Handled && sender is ScrollViewerSide view)
{
view.OnMouseHorizontalWheel(e);
}
}
protected virtual void OnMouseHorizontalWheel(MouseHorizontalWheelEventArgs e)
{
if (e.HorizontalDelta < 0)
{
ScrollToHorizontalOffset(HorizontalOffset + HORIZONTAL_SCROLL_OFFSET);
}
else
{
ScrollToHorizontalOffset(HorizontalOffset - HORIZONTAL_SCROLL_OFFSET);
}
}
#endregion
#region Stuff needed for horizontal scrolling
private static readonly HashSet<IntPtr> HOOKED_WINDOWS = new HashSet<IntPtr>();
private static void EnableMouseHorizontalWheelSupport(Window window)
{
if (window == null)
{
throw new ArgumentNullException(nameof(window));
}
if (window.IsLoaded)
{
IntPtr handle = new WindowInteropHelper(window).Handle;
EnableMouseHorizontalWheelSupport(handle);
}
else
{
window.Loaded += (sender, args) => {
IntPtr handle = new WindowInteropHelper(window).Handle;
EnableMouseHorizontalWheelSupport(handle);
};
}
}
private static void EnableMouseHorizontalWheelSupport(IntPtr handle)
{
if (!HOOKED_WINDOWS.Contains(handle))
{
HOOKED_WINDOWS.Add(handle);
HwndSource source = HwndSource.FromHwnd(handle);
source?.AddHook(WndProcHook);
}
}
private static void HandleMouseHorizontalWheel(IntPtr wParam)
{
int tilt = -Win32.HiWord(wParam);
if (tilt == 0)
{
return;
}
IInputElement element = Mouse.DirectlyOver;
if (element != null)
{
MouseHorizontalWheelEventArgs ev = new MouseHorizontalWheelEventArgs(Mouse.PrimaryDevice, Environment.TickCount, tilt)
{
RoutedEvent = PreviewMouseHorizontalWheelEvent
};
element.RaiseEvent(ev);
if (ev.Handled)
{
return;
}
ev.RoutedEvent = MouseHorizontalWheelEvent;
element.RaiseEvent(ev);
}
}
private static IntPtr WndProcHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == Win32.WM_MOUSEHWHEEL)
{
HandleMouseHorizontalWheel(wParam);
}
return IntPtr.Zero;
}
private static class Win32
{
public const int WM_MOUSEHWHEEL = 0x020E;
private static int GetIntUnchecked(IntPtr value)
{
return IntPtr.Size == 8 ? unchecked((int)value.ToInt64()) : value.ToInt32();
}
public static int HiWord(IntPtr ptr)
{
return unchecked((short)((uint)GetIntUnchecked(ptr) >> 16));
}
}
#endregion
}
#region Handler / Event Args
public delegate void MouseHorizontalWheelEventHandler(object sender, MouseHorizontalWheelEventArgs e);
public class MouseHorizontalWheelEventArgs : MouseEventArgs
{
public int HorizontalDelta { get; }
public MouseHorizontalWheelEventArgs(MouseDevice mouse, int timestamp, int horizontalDelta)
: base(mouse, timestamp)
{
HorizontalDelta = horizontalDelta;
}
}
#endregion
}
答案 0 :(得分:2)
在自定义InvokeEventHandler
类中覆盖MouseEventArgs
方法:
public class MouseHorizontalWheelEventArgs : MouseEventArgs
{
public int HorizontalDelta { get; }
public MouseHorizontalWheelEventArgs(MouseDevice mouse, int timestamp, int horizontalDelta)
: base(mouse, timestamp)
{
HorizontalDelta = horizontalDelta;
}
protected override void InvokeEventHandler(Delegate genericHandler, object genericTarget)
{
MouseHorizontalWheelEventHandler handler = (MouseHorizontalWheelEventHandler)genericHandler;
handler(genericTarget, this);
}
}