Search code examples
wpflistviewscrollviewermouseleftbuttondown

WPF ListView and ScrollViewer hide MouseLeftButtonDown


To demostrate the problem I have this Xaml:

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

and the event handlers are :

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


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

When you run the app and click on the words TextBlock you get MouseDown fired followed by MouseUp. So far so good. But when you click on the words ListViewItem only MouseUp is fired. Same problem for ScrollViewer (List view includes it so I am guessing it's the same problem). Does anybody know why and if this can be fixed. By fixed I mean get it to fire not try to use another event or another mechanism all together.


Solution

  • First the problem: As suspected the problem is in 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);
        }
    

    As you can see it sets MouseButtonEventArgs.Handled to true which stops the bubbling of the event.

    Now the solution - it is in the way you add the handler:

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

    Note the last parameter (true) it causes the handler to be invoked even if the EventArgs.Hanlded was set to true. Then you can reset it:

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