PreviewMouseWheel事件中给出错误的发件人

时间:2014-12-23 11:12:24

标签: c# wpf events sender

我不会在这里发布我的代码,而是在程序中概述基本树。 我有一个带有Item的TabControl和一些“treed”元素如下:

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.exe中出现“System.NullReferenceException”类型的异常,但未在用户代码中处理。附加信息:对象引用未设置为对象的实例。

我注意到sender实际上不是myGrid,而是标记为{System.Windows.Controls.TabControl Items.Count:1}。但是如果我明确地将事件添加到myGrid,那怎么可能呢?我可能在这里错过了其他什么吗?

我尝试使用MouseWheel而不是PreviewMouseWheel,它给了我同样的问题,e.Sourcee.OriginalSource都不是myGrid,而是{{} 1}}和"my UserControl",重新分配。

我发现的另一篇与此类似的帖子是here,但不幸的是,这不是我的问题。

希望有人可以帮助我,因为我真的迷路了...

2 个答案:

答案 0 :(得分:1)

您使用过隧道事件,因此可以预期您发现的行为。来自MSDN上的Routed Events Overview页:

  

隧道:最初,调用元素树根的事件处理程序。然后,路由事件沿着路径行进通过连续子元素的路径,朝向作为路由事件源的节点元素(引发路由事件的元素)。隧道路由事件通常被用作或作为控件的合成的一部分来处理,使得来自复合部件的事件可被故意抑制或由完全控制特定的事件替换。 WPF中提供的输入事件通常实现为隧道/冒泡对。隧道事件有时也称为预览事件,因为用于对的命名约定。

Intead,您可以使用相关的Bubbling事件MouseWheel。再次,从链接页面:

  

冒泡:调用事件源上的事件处理程序。然后路由事件路由到连续的父元素,直到到达元素树根。大多数路由事件使用冒泡路由策略。冒泡路由事件通常用于报告来自不同控件或其他UI元素的输入或状态更改。

当然,因为它仍然是RoutedEvent,它仍然可以由父元素调用。您最好的选择是在投射之前检查senderScrollViewer,还是经常在e.OriginalSource对象的MouseWheelEventArgs属性中找到所需的UI元素相反或在sender参数中。

答案 1 :(得分:1)

修改 根据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的内容,而不仅仅是在那里创建的事件。

你可以做什么来保存对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();
 }