WPF ListView 和 ScrollViewer 隐藏 MouseLeftButtonDown

WPF ListView and ScrollViewer hide MouseLeftButtonDown

为了演示问题,我有这个 Xaml:

    <DockPanel MouseLeftButtonDown="DockPanel_MouseLeftButtonDown"  MouseLeftButtonUp="DockPanel_MouseLeftButtonUp">
        <ListView>
            <ListViewItem>ListViewItem</ListViewItem>
        </ListView>
        <TextBlock>TextBlock</TextBlock>
    </DockPanel>

事件处理程序是:

    private void DockPanel_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        Console.WriteLine("DockPanel_MouseLeftButtonDown");
    }


    private void DockPanel_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        Console.WriteLine("DockPanel_MouseLeftButtonUp");
    }

当您 运行 应用程序并单击 TextBlock 字样时,您会触发 MouseDown,然后触发 MouseUp。到目前为止,一切都很好。但是,当您单击 ListViewItem 时,只会触发 MouseUp。 ScrollViewer 也有同样的问题(列表视图包括它,所以我猜这是同样的问题)。 有谁知道为什么以及是否可以解决这个问题。 固定的我的意思是让它触发而不是尝试一起使用另一个事件或另一个机制。

首先是问题: 怀疑问题出在 ScrollViewer 中:http://referencesource.microsoft.com/#PresentationFramework/Framework/System/Windows/Controls/ScrollViewer.cs,488ab4a977a015eb

    protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
    {
        if (Focus())
            e.Handled = true;
        base.OnMouseLeftButtonDown(e);
    }

如您所见,它将 MouseButtonEventArgs.Handled 设置为 true 以停止事件的冒泡。

现在解决方案 - 就是您添加处理程序的方式:

        MyListView.AddHandler(
            ListView.MouseLeftButtonDownEvent, 
            new MouseButtonEventHandler(ListView_MouseLeftButtonDown),
            true);

请注意最后一个参数 (true),它会导致调用处理程序,即使 EventArgs.Hanlded 设置为 true。 然后你可以重置它:

    private void ListView_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        e.Handled = false;
    }

当 ScrollViewer 阻止我的 MouseLeftButtonDown 事件时,我遇到了一些类似的情况。我有一个包含在 ScrollViewer 中的内容控件:

<ScrollViewer VerticalScrollBarVisibility="Auto">
     <ContentControl x:Name="Details"  />
 </ScrollViewer>

这是 Popup 的内部,具有 drag/drop 行为。所以,因为我的行为没有收到这个事件,所以它不起作用。当我将 IsHitTestVisible="True" 添加到 ScrollViewer 时,我的行为开始起作用,但当然我的 ContentControl 没有响应任何点击。然后我看到了这个:

protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
    if (Focus())
        e.Handled = true;
    base.OnMouseLeftButtonDown(e);
}

并尝试添加 Focusable="False" 以从我的点击中排除 ScrollViewer - 它有效。我的行为正常,ContentControl 内部的控件正在获取所有鼠标事件。

 <ScrollViewer VerticalScrollBarVisibility="Auto" Focusable="False">
     <ContentControl x:Name="Details"  />
 </ScrollViewer>

希望对大家有所帮助。