Il test di input hit produce risultati non corretti su un elemento Path con fattori di ridimensionamento elevati nella sua proprietà RenderTransform
.Test hit errato sul percorso trasformato
Il seguente XAML definisce un percorso con un cerchio pieno e un cursore 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>
Come si può vedere nell'immagine sottostante, il cursore Hand
appare anche se la sua posizione è senso all'esterno della forma.
con un percorso di grandi e piccoli fattori di scala il problema scompare e il cursore si comporta come previsto.
<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>
Esecuzione di un hit test esplicito come questo
private void Canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var canvas = (UIElement)sender;
var hitElement = canvas.InputHitTest(e.GetPosition(canvas));
Trace.TraceInformation("hitElement = {0}", hitElement);
}
in un gestore di eventi del mouse sulla tela dà gli stessi risultati non corretti. Un clic del mouse chiaramente fuori dal percorso in scala restituisce comunque il percorso come elemento colpito.
Vale anche la pena notare che il problema non viene visualizzato in Silverlight.
Ora la domanda è: qual è la causa di questo comportamento e come può essere evitato? Nota che non posso semplicemente cambiare le dimensioni originali dei miei elementi Path, quindi una risposta del tipo "non utilizzare fattori su larga scala" non sarà utile.
La mia soluzione corrente non è quella di trasformare il percorso da un RenderTransform, ma trasformare i Dati invece (applicando la trasformazione alla proprietà Geometry.Transform
). Ma poiché potrebbero esserci riempimenti complessi (ad esempio con ImageBrush), devo anche trasformare i pennelli di riempimento (il che implica non solo l'impostazione della loro trasformazione, ma anche il loro punto di vista).
Inoltre, la trasformazione effettiva non è solo ridimensionamento, ma un MatrixTransform che ruota e converte anche.
Potrebbe anche valere la pena notare che il problema emerge anche con altre geometrie e trasformazioni aggiuntive. Ad esempio, un tracciato trasformato con RectangleGeometry mostra un comportamento simile errato.
non corretti con fattori di grandi dimensioni:
<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>
corrette con i fattori di piccola scala:
<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>
Soluzione: * Non utilizzare fattori di scala di grandi dimensioni *. Nah, sto scherzando. Si verifica se si cambia 'RenderTranform' in' LayoutTransform'? –
Già provato, sebbene LayoutTransform non sia un'opzione. Ad ogni modo, si comporta allo stesso modo con LayoutTransform. – Clemens
Hai considerato l'utilizzo di 'RectangleGeometry.Transform' invece di' Path. [Render | Layout] Transform'? Dal momento che hai accesso alla geometria stessa, puoi fare in modo che Shape esegua il rendering di una geometria già trasformata, quindi i test di hit dovrebbero essere più naturali. – heltonbiker