wpfscrollviewermouseleftbuttondown

Canvas in ScrollViewer (Preview)MouseButtonDown event order


If we have

<ScrollViewer Name="scroll_viewer" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
    <Canvas Name="canvas" Height="200" Width="200">
        <Rectangle Fill="AliceBlue" Width="100" Height="100"/>  
    </Canvas>
</ScrollViewer> 

with handlers for:

scroll_viewer.PreviewMouseLeftButtonDown
scroll_viewer.MouseLeftButtonDown
canvas.PreviewMouseLeftButtonDown

Then if we click in the Rectangle we get scroll_viewer_PreviewMouseLeftButtonDown called first then canvas_PreviewMouseLeftButtonDown but scroll_viewer_MouseLeftButtonDown is not called.
I want to handle the click event first in the canvas - if an object is clicked I want to handled the event (for object drag). If no canvas object is clicked I want to handle event in scroll_viewer (to manage scrollview panning with the mouse).
How to manage this given that the call order is the oposite of what i want and that the non perview version scroll_viewer.MouseLeftButtonDown is not called?

UPDATE:
From this post: Silverlight forums

((FrameworkElement)scroll_viewer.GetValue(ScrollViewer.ContentProperty)).MouseLeftButtonDown += scroll_viewer_MouseLeftButtonDown;

DOES work ie does get called after the preview events - can some explain why this less than obvious syntax is required?


Solution

  • The problem is that the ScrollViewer already handles the MouseLeftButtonDown event internally, like so:

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

    You can "fix" this using a custom class, like so:

    public class MyScrollViewer : ScrollViewer {
    
        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) {
            base.OnMouseLeftButtonDown(e);
            e.Handled = false;
        }
    }
    

    SIDE NOTE: You should use x:Name in XAML, not Name. Otherwise you may run into compilation errors using the above class.

    Alternatively, you could attach your handler for all MouseLeftButtonDown events, including handled ones. So instead of:

    this.scroll_viewer.MouseLeftButtonDown += new MouseButtonEventHandler(scroll_viewer_MouseLeftButtonDown);
    

    You'd use:

    this.scroll_viewer.AddHandler(ScrollViewer.MouseLeftButtonDownEvent, new MouseButtonEventHandler(this.scroll_viewer_MouseLeftButtonDown), true);