wpf xaml 2d resize centering

WPF: cambiar el tamaño de un círculo, manteniendo el punto central en lugar de TopLeft?



xaml 2d (5)

Me gustaría cambiar el tamaño de un círculo en mi lienzo con la ayuda de un control deslizante. Este círculo se puede mover en el lienzo por algunas cosas de arrastrar y soltar que hice en el código detrás, por lo que su posición no es fija.

He vinculado el valor del control deslizante a la altura y el ancho de una elipse. Lamentablemente, cuando utilizo el control deslizante, el círculo se redimensiona con su punto superior izquierdo (en realidad, el punto superior izquierdo del rectángulo en el que está sentado) permaneciendo igual durante la operación.

Me gustaría cambiar el tamaño con su punto central siendo constante durante la operación. ¿Hay alguna manera fácil de hacer esto en XAML? Por cierto, ya probé ScaleTransform, pero no hizo exactamente lo que quería.

¡Gracias un montón! :-)

Ene

<Canvas x:Name="MyCanvas"> <!-- this is needed for some adorner stuff I do in code behind --> <AdornerDecorator Canvas.Left="10" Canvas.Top="10"> <Ellipse x:Name="myEllipse" Height="{Binding Path=Value, ElementName=mySlider}" Width="{Binding Path=Value, ElementName=mySlider}" Stroke="Aquamarine" Fill="AliceBlue" RenderTransformOrigin="0.5 0.5"> <Ellipse.RenderTransform> <RotateTransform Angle="{Binding Path=Value, ElementName=myRotationSlider}" /> </Ellipse.RenderTransform> </Ellipse> </AdornerDecorator> <Slider x:Name="mySlider" Maximum="100" Minimum="0" Width="100" Value="10" Canvas.Left="150" Canvas.Top="10" /> <Slider x:Name="myRotationSlider" Maximum="360" Minimum="0" Width="100" Value="0" Canvas.Left="150" Canvas.Top="50" /> </Canvas>


Como está utilizando un lienzo, la ubicación que tiene un elemento es la ubicación. Si desea que la posición Superior e Izquierda cambie, debe hacerlo usted mismo. Si estuviera usando otro tipo de Panel, como una Rejilla, podría cambiar la alineación de su Elipse para colocarla en la misma ubicación relativa sin importar el tamaño. Podría obtener ese efecto agregando una cuadrícula dentro de AdornerDecorator y centrando la Elipse, pero también tendría que configurar AdornerDecorator o Grid en un tamaño fijo porque no se estirarán en un lienzo.

La mejor solución que podría usar sería una ScaleTransform aplicada a la propiedad RenderTransform con una RenderTransformOrigin de 0.5,0.5. Dijiste que tenías problemas con ScaleTransform pero no cuál era el problema.


El problema es que está utilizando el DESLIZADOR para ajustar el ancho y la altura. El ancho y la altura no se calculan en RenderTransformOrigin; solo RenderTransforms usa ese valor.

Aquí hay una versión corregida (brb, kaxaml):

<Canvas x:Name="MyCanvas"> <!-- this is needed for some adorner stuff I do in code behind --> <AdornerDecorator Canvas.Left="50" Canvas.Top="50"> <Ellipse x:Name="myEllipse" Width="10" Height="10" Fill="AliceBlue" RenderTransformOrigin="0.5 0.5" Stroke="Aquamarine"> <Ellipse.RenderTransform> <TransformGroup> <RotateTransform Angle="{Binding Path=Value, ElementName=myRotationSlider}"/> <ScaleTransform CenterX=".5" CenterY=".5" ScaleX="{Binding Path=Value, ElementName=mySlider}" ScaleY="{Binding Path=Value, ElementName=mySlider}"/> </TransformGroup> </Ellipse.RenderTransform> </Ellipse> </AdornerDecorator> <Slider x:Name="mySlider" Width="100" Canvas.Left="150" Canvas.Top="10" Maximum="10" Minimum="0" SmallChange=".01" Value="1"/> <Slider x:Name="myRotationSlider" Width="100" Canvas.Left="150" Canvas.Top="50" Maximum="360" Minimum="0" Value="0"/> </Canvas>

Por supuesto, esto probablemente no funcione para usted. ¿Por qué? Bueno, ScaleTransform usé zooms no solo del círculo sino también del borde; a medida que el círculo se hace más grande, el borde también lo hace. Espero que no te importe esto.

Además, tenga en cuenta al combinar las transformaciones (en este caso, la escala se rota) que se aplican en orden, y una puede afectar cómo se hace otra. En tu caso, no notarías esto. Pero si, por ejemplo, hiciera una rotación y traduzca, el orden sería relevante.

Ah, ¿qué estaba pensando? Simplemente coloque la elipse en una rejilla (la solución más simple pero otros recipientes funcionarían). La cuadrícula se ocupa automáticamente de centrar la elipse a medida que se redimensiona. ¡Sin necesidad de ningún convertidor de valor! Aquí está el código:

<Canvas x:Name="MyCanvas"> <!-- this is needed for some adorner stuff I do in code behind --> <Grid Width="100" Height="100"> <AdornerDecorator> <Ellipse x:Name="myEllipse" Width="{Binding Path=Value, ElementName=mySlider}" Height="{Binding Path=Value, ElementName=mySlider}" Fill="AliceBlue" RenderTransformOrigin="0.5 0.5" Stroke="Aquamarine"> <Ellipse.RenderTransform> <RotateTransform Angle="{Binding Path=Value, ElementName=myRotationSlider}"/> </Ellipse.RenderTransform> </Ellipse> </AdornerDecorator> </Grid> <Slider x:Name="mySlider" Width="100" Canvas.Left="150" Canvas.Top="10" Maximum="100" Minimum="0" Value="10"/> <Slider x:Name="myRotationSlider" Width="100" Canvas.Left="150" Canvas.Top="50" Maximum="360" Minimum="0" Value="0"/> </Canvas>


Envuelva su Elipse en una cuadrícula del tamaño máximo. Mientras sea más pequeño, la Elipse estará centrada en la Grilla:

<Grid Canvas.Left="10" Canvas.Top="10" Width="100" Height="100"> <AdornerDecorator> <Ellipse x:Name="myEllipse" Height="{Binding Path=Value, ElementName=mySlider}" Width="{Binding Path=Value, ElementName=mySlider}" Stroke="Aquamarine" Fill="AliceBlue" RenderTransformOrigin="0.5 0.5"> <Ellipse.RenderTransform> <RotateTransform Angle="{Binding Path=Value, ElementName=myRotationSlider}" /> </Ellipse.RenderTransform> </Ellipse> </AdornerDecorator> </Grid>

Puede que necesite ajustar su lógica de arrastre para manejar el arrastre de la cuadrícula en lugar de la elipse.


Puede unir su Canvas.Left y Canvas.Top a su altura y ancho mediante un ValueConverter.

Específicamente (editar):
Crea una propiedad para Canvas.Left y Canvas.Top y únelas a estas.
Almacene los valores anteriores para Ancho y alto o el antiguo valor del control deslizante.
Siempre que se cambie el control deslizante, obtenga el cambio incremental "dx" restando el valor almacenado.
(No olvides actualizar el valor almacenado ...)
Agregue dx a la propiedad Anchura y Altura.
Y, como dijo Will, agregue dx / 2 * -1 a las propiedades Canvas.Left y Canvas.Top.

¿Tiene sentido?