Неправильное тестирование на измененный путь

Вводное тестирование результатов приводит к неправильным результатам в элементе Path с большими масштабными коэффициентами в свойстве RenderTransform.

Следующий XAML определяет Путь с заполненным кругом и курсором Hand.

<Canvas Background="LightGray">
    <Path StrokeThickness="0" Fill="Blue" Cursor="Hand">
        <Path.Data>
            <EllipseGeometry RadiusX=".5" RadiusY=".5" Center="1,1"/>
        </Path.Data>
        <Path.RenderTransform>
            <ScaleTransform ScaleX="150" ScaleY="150"/>
        </Path.RenderTransform>
    </Path>
</Canvas>

Как видно на изображении ниже, появляется курсор Hand, хотя его положение вне формы.

enter image description here

С более крупным путём и меньшими масштабными факторами проблема исчезает, и курсор ведет себя так, как ожидалось.

<Canvas Background="LightGray">
    <Path StrokeThickness="0" Fill="Blue" Cursor="Hand">
        <Path.Data>
            <EllipseGeometry RadiusX="50" RadiusY="50" Center="100,100"/>
        </Path.Data>
        <Path.RenderTransform>
            <ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
        </Path.RenderTransform>
    </Path>
</Canvas>

enter image description here

Выполнение явного теста теста, подобного этому

private void Canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    var canvas = (UIElement)sender;
    var hitElement = canvas.InputHitTest(e.GetPosition(canvas));
    Trace.TraceInformation("hitElement = {0}", hitElement);
}

в обработчике событий мыши на Canvas дает те же неверные результаты. Щелчок мыши явно за пределами масштабированного пути по-прежнему возвращает элемент "Путь" как элемент удара.

Также стоит отметить, что проблема не появляется в Silverlight.


Теперь возникает вопрос: в чем причина такого поведения и как его можно избежать? Обратите внимание, что я не могу просто изменить исходные размеры элементов Path, поэтому ответ, подобный "не использовать масштабные факторы", не будет полезен.

Моим текущим обходным путем является не преобразование пути в RenderTransform, а преобразование данных вместо этого (путем применения преобразования к свойству Geometry.Transform). Но поскольку может быть сложное заполнение (например, с помощью ImageBrush), мне также необходимо преобразовать кисти заливки (что связано не только с установкой их преобразования, но и с их окном просмотра).

Более того, фактическое преобразование - это не только масштабирование, но и матричная трансформация, которая также вращается и преобразуется.


Можно также отметить, что проблема также возникает с другими геометриями и дополнительными преобразованиями. Например, преобразованный Путь с RectangleGeometry показывает аналогично неправильное поведение.

Неправильно с крупномасштабными факторами:

<Canvas Background="LightGray">
    <Path StrokeThickness="0" Fill="Blue" Cursor="Hand">
        <Path.Data>
            <RectangleGeometry Rect=".5,.5,1,1"/>
        </Path.Data>
        <Path.RenderTransform>
            <TransformGroup>
                <ScaleTransform ScaleX="150" ScaleY="150"/>
                <RotateTransform Angle="45" CenterX="150" CenterY="150"/>
                <TranslateTransform X="100"/>
            </TransformGroup>
        </Path.RenderTransform>
    </Path>
</Canvas>

enter image description here

Исправить с помощью небольших масштабных коэффициентов:

<Canvas Background="LightGray">
    <Path StrokeThickness="0" Fill="Blue" Cursor="Hand">
        <Path.Data>
            <RectangleGeometry Rect="50,50,100,100"/>
        </Path.Data>
        <Path.RenderTransform>
            <TransformGroup>
                <ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
                <RotateTransform Angle="45" CenterX="150" CenterY="150"/>
                <TranslateTransform X="100"/>
            </TransformGroup>
        </Path.RenderTransform>
    </Path>
</Canvas>

enter image description here

Ответ 1

Больше расширенного комментария, чем ответ:

Это похоже на странное поведение, у меня была игра с некоторыми Paths, и я попытался использовать Geometry.GetWidenedPathGeometry, чтобы применить немного другое масштабирование влияние на данные, но не очень далеко.

Основная причина проблемы, по-видимому, заключается в том, что в WPF выбран толерантность обнаружения попадания, есть два ответа на подобные вопросы в MSDN от Брендана Кларка, это похоже на то, что никогда не было исправлено.

По существу, применяемый допуск на тестирование ударов, по-видимому, является абсолютным значением, полученным из базового размера самой геометрии, а не для визуализированного/преобразованного размера. Таким образом, в то время как это прекрасно для больших фигур, которые вы делаете меньшими или даже маленькими фигурами, которые вы держите маленькими, начнет становиться довольно неточным, когда маленькие фигуры масштабируются (как вы уже нашли).

т.е. Небольшой критерий тестирования ударов относительно размера маленькой фигуры в порядке, но когда форма и допуск расширяются, это начинает выглядеть ужасно.

Предлагаемое решение в одном потоке состояло в том, чтобы масштабировать фигуры до максимального размера, необходимого вам, и уменьшать их, когда вы хотите, чтобы они были меньше (что не является для вас решением). Ео.

Похоже, вы можете застрять в каком-то преобразовании. Я попытаюсь посмотреть, смогу ли я придумать что-нибудь лучше.

Ссылки, на которые я смотрел:

http://social.msdn.microsoft.com/Forums/vstudio/en-US/8708e340-f734-4cf4-b91d-28b49fee2b72/hittest-is-buggy-not-accurate-for-transformed-scaled-etc-visuals?forum=wpf

http://social.msdn.microsoft.com/Forums/vstudio/en-US/b307676b-d8b2-4af0-9f6f-1e150eed97ba/hittesting-with-a-scaled-path-doesnt-work?forum=wpf