Canvas в ScrollViewer (предварительная версия) Порядок событий MouseButtonDown

Если мы имеем

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

с обработчиками для:

scroll_viewer.PreviewMouseLeftButtonDown
scroll_viewer.MouseLeftButtonDown
canvas.PreviewMouseLeftButtonDown

Затем, если мы щелкнем в прямоугольнике, мы сначала вызовем scroll_viewer_PreviewMouseLeftButtonDown, затем canvas_PreviewMouseLeftButtonDown, но scroll_viewer_MouseLeftButtonDown не вызывается.
Я хочу сначала обработать событие щелчка на холсте - если объект щелкнут, я хочу обработать событие (для перетаскивания объекта ). Если ни один объект холста не нажат, я хочу обработать событие в scroll_viewer (для управления панорамированием прокрутки с помощью мыши).
Как справиться с этим, учитывая, что порядок вызовов противоположен тому, что я хочу, и что версия без perview scroll_viewer.MouseLeftButtonDown не звонил?

ОБНОВЛЕНИЕ:
Из этого сообщения: форумы Silverlight

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

РАБОТАЕТ ЛИ, т.е. вызывается после событий предварительного просмотра - могут ли некоторые объяснить, почему требуется этот менее очевидный синтаксис?


person Ricibob    schedule 28.10.2011    source источник


Ответы (2)


Проблема в том, что ScrollViewer уже внутренне обрабатывает событие MouseLeftButtonDown, например:

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

Вы можете «исправить» это, используя собственный класс, например:

public class MyScrollViewer : ScrollViewer {

    protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) {
        base.OnMouseLeftButtonDown(e);
        e.Handled = false;
    }
}

ПРИМЕЧАНИЕ. В XAML следует использовать x:Name, а не Name. В противном случае вы можете столкнуться с ошибками компиляции при использовании вышеуказанного класса.

В качестве альтернативы вы можете прикрепить свой обработчик для всех событий MouseLeftButtonDown, включая обработанные. Итак, вместо:

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

Вы бы использовали:

this.scroll_viewer.AddHandler(ScrollViewer.MouseLeftButtonDownEvent, new MouseButtonEventHandler(this.scroll_viewer_MouseLeftButtonDown), true);
person CodeNaked    schedule 28.10.2011

События Preview следуют стратегии маршрутизации, аналогичной стратегии Tunneling, что означает, что событие начинается с вершины дерева элементов и перемещается по нему вниз. Таким образом, сначала он попадет в ваш ScrollViewer, а затем в ваш Canvas.

События без предварительного просмотра следуют стратегии маршрутизации, аналогичной стратегии Bubbling, что означает, что события начинаются с объекта, на котором они произошли, и перемещаются вверх по дереву элементов. В этом случае сначала будет затронут Canvas, а затем ScrollViewer.

Подробнее о стратегиях маршрутизации можно прочитать здесь

В качестве примечания: чтобы объекты Canvas были видны для событий HitTest, они должны иметь непрозрачный фон. Поэтому, если у вас есть Canvas без указанного цвета фона, по умолчанию он будет прозрачным и не будет отображаться для HitTests.

person Rachel    schedule 28.10.2011
comment
+1 Для прозрачной / самой популярной вещи - я заметил, что с холстом по умолчанию, если нет объекта для щелчка, тогда нет вызова события. - person Ricibob; 28.10.2011