【发布时间】:2013-10-11 17:36:16
【问题描述】:
在 RenderTransform 属性中具有较大比例因子的 Path 元素上,输入命中测试会产生不正确的结果。
以下 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 光标出现了,尽管它的位置在形状之外。
使用更大的路径和更小的比例因子,问题消失并且光标按预期运行。
<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>
像这样执行显式命中测试
private void Canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var canvas = (UIElement)sender;
var hitElement = canvas.InputHitTest(e.GetPosition(canvas));
Trace.TraceInformation("hitElement = {0}", hitElement);
}
在画布上的鼠标事件处理程序中会给出相同的错误结果。在缩放的 Path 之外清晰地单击鼠标仍会将 Path 作为命中元素返回。
另外值得注意的是,Silverlight 中并未出现该问题。
现在的问题是:这种行为的原因是什么,如何避免?请注意,我不能简单地更改路径元素的原始大小,因此“不要使用大比例因子”之类的答案不会有帮助。
我当前的解决方法不是通过 RenderTransform 转换路径,而是转换数据(通过将转换应用于 Geometry.Transform 属性)。但由于可能有复杂的填充(例如使用 ImageBrush),我也必须变换填充画笔(这不仅涉及设置它们的变换,还涉及它们的视口)。
此外,实际的变换不仅仅是缩放,而是一个 MatrixTransform,它也可以旋转和平移。
还需要注意的是,其他几何形状和其他变换也会出现问题。例如,带有 RectangleGeometry 的转换后的 Path 显示出类似的错误行为。
大比例因子不正确:
<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>
用小比例因子校正:
<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>
【问题讨论】:
-
解决方案:不要使用大比例因子。不,开个玩笑。把
RenderTranform改成LayoutTransform会出现这种情况吗? -
已经尝试过了,尽管 LayoutTransform 不是一个选项。无论如何,它的行为与 LayoutTransform 相同。
-
您是否考虑过使用
RectangleGeometry.Transform而不是Path.[Render|Layout]Transform?由于您可以访问几何体本身,因此您可以让 Shape 渲染已转换的几何体,然后命中测试应该更自然。 -
@heltonbiker 是的,我已经这样做了。我在问题中提到它作为“我目前的解决方法”。我也解释了为什么不令人满意。