2013-10-11 20 views
11

輸入命中測試在其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雖然其位置在形狀以外的方式。

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); 
} 
在畫布上的鼠標事件處理

給出了同樣的結果不正確。在縮放的路徑之外清楚地單擊鼠標仍然返回Path作爲命中元素。

還值得一提的是,問題並未出現在Silverlight中。


現在的問題是:這種行爲的原因是什麼?如何避免?請注意,我不能簡單地更改我的路徑元素的原始大小,因此諸如「不使用大比例因子」的答案不會有幫助。

我當前的解決方法是不通過RenderTransform轉換路徑,而是轉換數據(通過將轉換應用於Geometry.Transform屬性)。但是由於可能有複雜的填充(例如使用ImageBrush),我也必須轉換填充畫筆(不僅涉及設置它們的轉換,還涉及它們的視口)。此外,實際轉換不僅僅是縮放,而且是一個MatrixTransform,它也可以旋轉和轉換。


也值得注意的是,這個問題也出現在其他幾何圖形和附加轉換中。例如,帶有矩形幾何的轉換路徑顯示類似的錯誤行爲。

錯誤與大規模因素:

<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

+0

解決辦法:不要使用大規模因素*。不,開玩笑吧。如果將'RenderTranform'更改爲'LayoutTransform',會發生嗎? –

+0

已經嘗試過,雖然LayoutTransform不會是一個選項。無論如何,它的行爲與LayoutTransform相同。 – Clemens

+0

您是否考慮過使用'RectangleGeometry.Transform'而不是'Path。[Render | Layout] Transform'?由於您可以訪問幾何圖形本身,因此可以讓Shape創建已轉換的幾何圖形,然後點擊測試應該更加自然。 – heltonbiker

回答

3

超過一個答案延長評論:

這似乎是一個奇怪的行爲,我玩了一些Paths,並嘗試使用Geometry.GetWidenedPathGeometry對數據本身應用略微不同的縮放效果,但沒有得到很大的迴應。

問題的根源似乎是在WPF中選擇命中檢測容忍的方式,Brendan Clark對MSDN上的類似問題有兩個答案,它似乎是某種從未被修復的東西。

基本上使用的命中測試容差似乎是從幾何本身的基本大小派生的絕對值,而不是渲染/轉換的大小。所以,儘管對於大尺寸的較小形狀,或者小尺寸的小形狀來說,這很好,但是當小形狀放大時(正如您找到的),它會開始變得相當不準確。

I.e.相對於小尺寸的小尺寸測試容差是很好的,但是當形狀和容差都被放大時,開始看起來很可怕。

在一個線程中提出的解決方案是將形狀縮放到您需要的最大尺寸,並在您希望它們更小時(這不是您的解決方案)縮小它們的大小。 EW。

看起來你可能會陷入一些轉變。我會試着看看我能不能做出更好的事情。

鏈接我一直在尋找:

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

+0

感謝您提供此解釋和鏈接。這就是我一直在尋找的。 – Clemens

+1

很高興這很有用= D – Chris