Блог переехал. Актуальная версия поста находится по адресу: http://aakinshin.net/ru/blog/dotnet/findelementsinhostcoordinates/.
Есть в Silverlight отличный метод: VisualTreeHelper.FindElementsInHostCoordinates — позволяет выполнять HitTest, т.е. для некоторой точки или прямоугольника искать все объекты визуального поддерева, которые с этими точкой или прямоугольником пересекаются. Внешне точно такой же метод VisualTreeHelper.FindElementsInHostCoordinates можно встретить в WinRT. И вроде выглядит-то он точно также, но есть нюанс: работает этот чудо-метод в разных версиях платформы по-разному. Давайте разберёмся.
Сначала создадим простое Silverlight 5 приложение. Основная вёрстка будет выглядеть следующим образом:
<Grid x:Name="LayoutRoot"> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="100"/> </Grid.RowDefinitions> <Canvas MouseLeftButtonDown="OnMainCanvasMouseLeftButtonDown" x:Name="MainCanvas" Background="LightGreen"> <Ellipse Width="200" Height="200" Fill="LightCoral" /> <Path Fill="LightBlue" Data="M 10,100 C 10,300 300,-200 300,100"/> </Canvas> <TextBlock Grid.Row="1" x:Name="StatusBlock" /> </Grid>
Тут всё очень просто: имеется Canvas
, а на нём лежит Ellipse
и Path
. Прямо под этим чудесным произведением искусства находится TextBlock
в который мы можем вывести что-нибудь полезное. Выглядит приложение следующим образом:
Теперь напишем обработчик события для клика мышкой по нашему Canvas
-элементу: будем искать элементы, в которые мы попали. Для этого нам пригодятся две версии VisualTreeHelper.FindElementsInHostCoordinates
(для точки и для прямоугольника):
public static IEnumerableFindElementsInHostCoordinates( Point intersectingPoint, UIElement subtree ) public static IEnumerable FindElementsInHostCoordinates( Rect intersectingRect, UIElement subtree )
Список полученных объектов будем выводить в StatusBlock
:
private void OnMainCanvasMouseLeftButtonDown(object sender, MouseButtonEventArgs e) { var p = e.GetPosition(MainCanvas); var listPoint = VisualTreeHelper.FindElementsInHostCoordinates( new Point(p.X, p.Y), MainCanvas).ToList(); var listRect = VisualTreeHelper.FindElementsInHostCoordinates( new Rect(p.X, p.Y, 1, 1), MainCanvas).ToList(); var strPoint = string.Join(", ", listPoint.Select(el => el.GetType().Name.ToString())); var strRect = string.Join(", ", listRect.Select(el => el.GetType().Name.ToString())); StatusBlock.Text = string.Format("[{0}] vs [{1}]", strPoint, strRect); }
Наше отличное приложение готово! Что-то внутри подсказывает, что ввиду размеров прямоугольника (1x1) результаты работы двух перегрузок метода не должны отличаться. Давайте проверим, потыкав в разные места. Следующая картинка показывает результаты проведённого опыта:
Ну, вроде всё хорошо, методы отработали, как и ожидалось. А теперь перейдём к WinRT. Создадим новое Windows Store приложение и снабдим его аналогичной вёрсткой:
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}"> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="100"/> </Grid.RowDefinitions> <Canvas Tapped="OnMainCanvasTapped" x:Name="MainCanvas" Background="LightGreen"> <Ellipse Width="200" Height="200" Fill="LightCoral" /> <Path Fill="LightBlue" Data="M 10,100 C 10,300 300,-200 300,100"/> </Canvas> <TextBlock Grid.Row="1" x:Name="StatusBlock" /> </Grid>
Код обработчика OnMainCanvasTapped
полностью совпадает с кодом OnMainCanvasMouseLeftButtonDown
. Давайте запустим приложение и потыкаем в него. Результаты:
Вот это поворот! Недолгое кликанье по приложению быстро подведёт нас к выводу: точечный HitTest работает точно также, как и в Silverlight, а вот HitTest по прямоугольнику для Path-фигур работает не по самой фигуре, а по её BoundingBox-у (ограничивающему прямоугольнику). WinRT-приложения делаются по принципу Touch First, так что наиболее интересна именно Rect-версия метода. В большинстве случаев этот момент скорее всего будет не особо принципиален, но вот если приложение ориентировано на взаимодействие с различными изогнутыми элементами, то на особенность такого поведения FindElementsInHostCoordinates
лучше бы обратить особое внимание.
Комментариев нет:
Отправить комментарий