سؤال

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?

هل كانت مفيدة؟

المحلول

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);

نصائح أخرى

The Preview events follow a routing strategy similar to the Tunneling strategy, meaning that the event starts at the top of the element tree, and travels down it. So it would hit your ScrollViewer first, then your Canvas.

The non-Preview events follow a routing strategy similar to the Bubbling strategy, meaning that events start on the object they occurred on, and travel up the element tree. In this case, the Canvas would get hit first, then the ScrollViewer.

You can read more about the Routing strategies here

As a side note, for Canvas objects to be visible for HitTest events, they need to have a non-transparent background. So if you have a Canvas with no background color specified, it will default to Transparent and not be visible for HitTests.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top