在预览鼠标滚轮事件中给出错误的发件人
本文关键字:错误 出错 鼠标 事件 | 更新日期: 2023-09-27 18:35:01
我不会在这里发布我的代码,而是在我的程序中概述基本树。我有一个 TabControl,里面有一个项目和一些"树状"元素,如下所示:
TabControl
->TabItem
->UserControl(Grid with Columns and Rows)
->ScrollViewer(Within one of the Grid.Columns/Grid.Rows, also part of the UserControl)
->Grid myGrid(added in code during runtime)
->...a couple more things
现在在代码中,我向myGrid
添加一个事件,当我尝试手动滚动ScrollViewer
时,我注意到了错误,仅在按下 ctrl 时。
myGrid.PreviewMouseWheel += HandlePreviewMouseWheel;
private void HandlePreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
e.Handled = true;
bool isCtrl = Keyboard.IsKeyDown(Key.LeftCtrl);
if (isCtrl)
{
if (e.Delta > 0)
((sender as Grid).Parent as ScrollViewer).LineUp();
else
((sender as Grid).Parent as ScrollViewer).LineDown();
}
}
这在类型转换上引发了一个异常:dfviewer 中发生了类型为"System.NullReferenceException"的异常.exe但未在用户代码中处理。其他信息:对象引用未设置为对象的实例。
我注意到sender
实际上不是myGrid
而是标记为{System.Windows.Controls.TabControl Items.Count:1}
。但是,如果我明确将事件添加到myGrid
,这怎么可能?我有可能在这里错过了其他东西吗?
我尝试使用MouseWheel
而不是PreviewMouseWheel
,它给了我同样的问题,e.Source
和e.OriginalSource
都不myGrid
而是"my UserControl"
和"some Child of myGrid"
,特别是。
发现的唯一与此有点相似的其他帖子在这里,但不幸的是,这不完全是我在这里的问题。
希望有人能帮助我,因为我真的迷路了......
您使用了隧道事件,因此您发现的行为是预期的。从 MSDN 上的"路由事件概述"页:
隧道:最初,在元素树根上调用事件处理程序。然后,路由事件沿着路由通过连续的子元素,到达作为路由事件源的节点元素(引发路由事件的元素(。隧道路由事件通常作为控件合成的一部分使用或处理,以便可以有意抑制来自复合部件的事件,或者将其替换为特定于完整控件的事件。WPF 中提供的输入事件通常作为隧道/冒泡对实现。隧道事件有时也称为预览事件,因为用于对的命名约定。
Intead,您可以使用相关的冒泡事件,MouseWheel
。同样,从链接页面:
冒泡:调用事件源上的事件处理程序。然后,路由事件路由到连续的父元素,直到到达元素树根。大多数路由事件使用冒泡路由策略。冒泡路由事件通常用于报告来自不同控件或其他 UI 元素的输入或状态更改。
当然,由于这仍然是一个RoutedEvent
,它仍然可以由父元素调用。最好的选择是在强制转换之前简单地检查sender
是否为ScrollViewer
,或者通常您会在MouseWheelEventArgs
对象的 e.OriginalSource
属性中找到所需的 UI 元素,或者在 sender
参数中找到所需的 UI 元素。
编辑:到 OP 的请求,将其更改为处理多个项目。
注册活动时:
ScrollViewer gridParent = myGrid.Parent as ScrollViewer;
myGrid.PreviewMouseWheel += (sender, args) => Grid_PreviewMouseWheel(sv, args);
在处理程序中,您已经获得了滚动查看器:
void Grid_PreviewMouseWheel(ScrollViewer scrollViewer, MouseWheelEventArgs e)
{
e.Handled=true;
bool isCtrl = Keyboard.IsKeyDown(Key.LeftCtrl);
if (isCtrl)
{
if (e.Delta > 0)
scrollViewer.LineUp();
else
scrollViewer.LineDown();
}
}
WPF 路由事件的行为略有不同,请尝试阅读 http://msdn.microsoft.com/en-us/library/ms742806%28v=vs.110%29.aspx#routing_strategies 以了解详细信息。
预览事件将遍历可视化树,你正在捕获到达 myGrid 的任何内容,而不仅仅是在那里创建的事件。
你可以做什么 si 保存对 myGrid 的引用:
ScrollViewer gridParent;
...
gridParent = myGrid.Parent as ScrollViewer;
myGrid.PreviewMouseWheel += HandlePreviewMouseWheel;
在处理程序代码中:
bool isCtrl = Keyboard.IsKeyDown(Key.LeftCtrl);
if (isCtrl)
{
if (e.Delta > 0)
gridParent.LineUp();
else
gridParent.LineDown();
}