WPF ListView и ScrollViewer скрывают 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 (представление списка включает в себя, так что я предполагаю, что это та же проблема). Кто-нибудь знает, почему и если это можно исправить. Под фиксированным я имею в виду заставить его срабатывать, а не пытаться использовать другое событие или другой механизм все вместе.

2 ответа

Решение

Первая проблема: как и предполагалось, проблема в 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, который имел поведение перетаскивания. Итак, поскольку мое поведение не получало это событие, оно не работало. Когда я добавил 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>

Надеюсь, это кому-нибудь поможет.

Другие вопросы по тегам