在预览鼠标滚轮事件中给出错误的发件人

本文关键字:错误 出错 鼠标 事件 | 更新日期: 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.Sourcee.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();
 }
相关文章: