子列表框的滚动触发父滚动查看器 'Scroll Changed' 事件

Parent Scroll-viewer 'Scroll Changed' event firing by Child List-box's Scroll

我在滚动查看器中有一个列表框。 Scroll Viewer 附加了一个 Scroll-Changed 侦听器,我在其中放置了一个:

MessageBox.Show("Something Happened!");

这是我的 WPF 代码:

        <ScrollViewer ScrollChanged="ScrollViewer_ScrollChanged" VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Disabled">
                <ListBox>
                    <ListBox.Items>
                        <ListBoxItem Content="item 2"/>
                        <ListBoxItem Content="item 2"/>
                        <ListBoxItem Content="item 2"/>
                        <ListBoxItem Content="item 2"/>
                        <ListBoxItem Content="item 2"/>
                        <ListBoxItem Content="item 2"/>
                        <ListBoxItem Content="item 2"/>
                        <ListBoxItem Content="item 2"/>
                        <ListBoxItem Content="item 2"/>
                        <ListBoxItem Content="item 2"/>
                        <ListBoxItem Content="item 2"/>
                        <ListBoxItem Content="item 2"/>
                        <ListBoxItem Content="item 2"/>
                        <ListBoxItem Content="item 2"/>
                    </ListBox.Items>
                </ListBox>
        </ScrollViewer>

现在的问题是,当我滚动 ListBox 时,ScrollViewer 的 'ScrollChanged' 事件以某种方式触发,向我显示 MessageBox => 发生了一些事情!

我试过启用或禁用 Horizo​​ntalScrollBar,但同样的事情发生了... 我的 VerticalScrollBar 现在被禁用了,我做到了 'Hidden',但现在它也隐藏了 ListBox 的垂直滚动条,我也无法通过鼠标滚轮滚动 ListBox

提前致谢...

发生这种情况是因为 ScrollViewer.ScrollChanged is a routed event。具体来说,这是一个冒泡事件,这意味着当它被引发时,它会在可视化树中向上移动(从引发它的较深元素,向上到根)寻找处理程序。

这让你可以做这样的事情:

<ListBox ScrollViewer.ScrollChanged="listBox_ScrollChanged"/>

因为 ListBox 在内部使用了 ScrollViewer,你可以在 ListBox 级别监听 ScrollChanged 事件并处理它,即使 ListBox不会为此本身公开事件。

当然,这也会导致您遇到的情况。幸运的是它很容易解决。在您的事件处理程序中,您可以使用 RoutedEventArgs.Source 来判断正在滚动的元素:

//Assuming the ScrollViewer you want to listen to is given the name "OutsideScrollViewer"

private void ScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
    if (object.ReferenceEquals(e.Source,  OutsideScrollViewer))
    {

    }
}