2010-11-18 18 views
10

¿Alguien sabe de una manera fácil de animar un movimiento desde la ubicación actual de una imagen a una nueva ubicación (X, Y) usando animación WPF sin XAML, 100% mediante programación? Y sin referencia a "esto" (con RegisterName, etc.).WPF. La forma más fácil de mover la imagen a (X, Y) programáticamente?

Estoy tratando de hacer una clase de extensión para que la Imagen haga cosas de animación en ella. Es bastante fácil cambiar las propiedades de ancho y alto a través de la animación, pero luego de buscar la animación de ubicación de un objeto, de repente se vuelve más avanzado.

Como es una clase de extensión, solo tendré una referencia al objeto de imagen real y las X e Y a las que quiero moverlo.

public static void MoveTo(this Image targetControl, double X, double Y, double Width, double Height){ 
//code here 
... 
} 

Actualización:

Gracias. Casi trabajando. Parece que GetTop y GetLeft devuelven 'NaN' no establecido explícitamente. Encontrado la solución en este mensaje: Canvas.GetTop() returning NaN

public static void MoveTo(this Image target, double newX, double newY) { 
       Vector offset = VisualTreeHelper.GetOffset(target); 
       var top = offset.Y; 
       var left = offset.X; 
       TranslateTransform trans = new TranslateTransform(); 
       target.RenderTransform = trans; 
       DoubleAnimation anim1 = new DoubleAnimation(0, newY - top, TimeSpan.FromSeconds(10)); 
       DoubleAnimation anim2 = new DoubleAnimation(0, newX - left, TimeSpan.FromSeconds(10)); 
       trans.BeginAnimation(TranslateTransform.YProperty, anim1); 
       trans.BeginAnimation(TranslateTransform.XProperty, anim2); 
     } 

que tenía que intercambiar dos de los valores (de) con 0. Asumo que debe ser porque en este contexto la esquina superior izquierda de la imagen es el origen? Pero ahora funciona.

+0

Gracias por la actualización. Fue agradable ver un ejemplo de cómo usar un Vector. –

Respuesta

20

Prueba esto:

public static void MoveTo(this Image target, double newX, double newY) 
{ 
    var top = Canvas.GetTop(target); 
    var left = Canvas.GetLeft(target); 
    TranslateTransform trans = new TranslateTransform(); 
    target.RenderTransform = trans; 
    DoubleAnimation anim1 = new DoubleAnimation(top, newY - top, TimeSpan.FromSeconds(10)); 
    DoubleAnimation anim2 = new DoubleAnimation(left, newX - left, TimeSpan.FromSeconds(10)); 
    trans.BeginAnimation(TranslateTransform.XProperty,anim1); 
    trans.BeginAnimation(TranslateTransform.YProperty,anim2); 
} 
+2

Esto solo funcionará si la imagen está dentro de un lienzo (obtener las propiedades Superior e Izquierda devolverá 0 en caso contrario). Si está utilizando un lienzo, puede establecer las propiedades Canvas.Top y Canvas.Left para moverlo. Para otro tipo de contenedor, puede establecer los márgenes (eurgh) o, como ha mencionado Dean, usar una transformación de traducción. – Guy

+3

Casi trabajando. Las propiedades izquierda y superior tenían que obtenerse de VisualTreeHelper.GetOffset (target) en su lugar, ya que GetTop y GetLeft devolvían 'NaN'. Solo queda un error. El comienzo de la animación parece comenzar en el doble de la ubicación actual. – Wolf5

+1

0 como el valor desde que se arregló. – Wolf5

3

Aquí está ... Cambia el tamaño y mueve un MediaElement bajo la Canvas. Con tan sólo introducir sus parámetros:

Storyboard story = new Storyboard(); 
DoubleAnimation dbWidth = new DoubleAnimation(); 
dbWidth.From = mediaElement1.Width; 
dbWidth.To = 600; 
dbWidth.Duration = new Duration(TimeSpan.FromSeconds(.25)); 

DoubleAnimation dbHeight = new DoubleAnimation(); 
dbHeight.From = mediaElement1.Height; 
dbHeight.To = 400; 
dbHeight.Duration = dbWidth.Duration; 

story.Children.Add(dbWidth); 
Storyboard.SetTargetName(dbWidth, mediaElement1.Name); 
Storyboard.SetTargetProperty(dbWidth, new PropertyPath(MediaElement.WidthProperty)); 

story.Children.Add(dbHeight); 
Storyboard.SetTargetName(dbHeight, mediaElement1.Name); 
Storyboard.SetTargetProperty(dbHeight, new PropertyPath(MediaElement.HeightProperty)); 

DoubleAnimation dbCanvasX = new DoubleAnimation(); 
dbCanvasX.From = 0; 
dbCanvasX.To = 5; 
dbCanvasX.Duration = new Duration(TimeSpan.FromSeconds(.25)); 

DoubleAnimation dbCanvasY = new DoubleAnimation(); 
dbCanvasY.From = 0; 
dbCanvasY.To = 5; 
dbCanvasY.Duration = dbCanvasX.Duration; 

story.Children.Add(dbCanvasX); 
Storyboard.SetTargetName(dbCanvasX, mediaElement1.Name); 
Storyboard.SetTargetProperty(dbCanvasX, new PropertyPath(Canvas.LeftProperty)); 

story.Children.Add(dbCanvasY); 
Storyboard.SetTargetName(dbCanvasY, mediaElement1.Name); 
Storyboard.SetTargetProperty(dbCanvasY, new PropertyPath(Canvas.TopProperty)); 

story.Begin(this); 

<Viewbox Stretch="Uniform" StretchDirection="Both" SnapsToDevicePixels="True"> 
     <Grid Width="640" Height="480" Name="MainLayout" SnapsToDevicePixels="True" Background="Black"> 
      <Canvas Width="640" Height="480" Name="MainCanvas" SnapsToDevicePixels="True"> 
       <MediaElement Height="171" HorizontalAlignment="Left" Name="mediaElement1" VerticalAlignment="Top" Width="337" LoadedBehavior="Manual" Margin="166,140,0,0" Canvas.Left="-162" Canvas.Top="-140" /> 
       <Button Canvas.Left="294" Canvas.Top="196" Content="Button" Height="23" Name="button1" Width="75" Click="button1_Click" /> 
      </Canvas> 
     </Grid> 
    </Viewbox> 

ACTUALIZACIÓN:

En lugar de MediaElement uso de esta línea:

<Rectangle Height="171" HorizontalAlignment="Left" Name="mediaElement1" VerticalAlignment="Top" Width="337" Margin="166,140,0,0" Canvas.Left="-162" Canvas.Top="-140" Fill="{DynamicResource {x:Static SystemColors.MenuBarBrushKey}}" /> 

y no se olvide de poner el C# código para:

private void button1_Click(object sender, RoutedEventArgs e) {} 

Puede utilizar MediaElement así, pero hay que definir un VideoClip ver algo;)

+0

Ya, puse este código en un nuevo elemento Ventana y agregué el código C# al evento button_click. El código funciona perfectamente bien, pero no realiza una animación. ¿Me he perdido algo? –

+1

@JohnC Sí lo hace. Verifica mi respuesta. No te olvides de votar ... –

+0

Me he vuelto un poco mejor en las animaciones de WPF en los últimos días. Lo intentaré de nuevo cuando llegue a casa. –

1

Este código se basa en la respuesta de @ DeanChalk.

Se mueve un Image contenida dentro de un Canvas (RFID_Token) en diagonal desde la parte superior derecha a la parte inferior izquierda, en el centro sobre otro Image dentro de un Canvas (RFID_Reader).

<Canvas> 
    <Canvas x:Name="RFID_Reader_Canvas"> 
     <Image x:Name="RFID_Reader" Source="RFID-Reader.png" Height="456" Width="682" Canvas.Left="37" Canvas.Top="524"/> 
    </Canvas> 
    <Canvas x:Name="RFID_Token_Canvas"> 
     <Image x:Name="RFID_Token" Source="RFID-Token.png" Height="268" Width="343" Canvas.Left="874" Canvas.Top="70"/> 
    </Canvas> 
</Canvas> 

var StartX = Canvas.GetLeft(RFID_Token); 
var StartY = Canvas.GetTop(RFID_Token); 

var EndX = RFID_Reader.Width/2 + Canvas.GetLeft(RFID_Reader) - StartX - (RFID_Token.Width/2); 
var EndY = RFID_Reader.Height/2 + Canvas.GetTop(RFID_Reader) - StartY - (RFID_Token.Height/2); 

var AnimationX = new DoubleAnimation(0, EndX, TimeSpan.FromSeconds(1)); 
var AnimationY = new DoubleAnimation(0, EndY, TimeSpan.FromSeconds(1)); 

var Transform = new TranslateTransform(); 
RFID_Token_Canvas.RenderTransform = Transform; 

Transform.BeginAnimation(TranslateTransform.XProperty, AnimationX); 
Transform.BeginAnimation(TranslateTransform.YProperty, AnimationY); 
0

Por favor, encontrar una solución que utiliza la izquierda y superior propiedades de lona para el método de extensión.Ver el siguiente código:

public static void MoveTo(this Image target, Point newP) 
    { 

     Point oldP = new Point(); 
     oldP.X = Canvas.GetLeft(target); 
     oldP.Y = Canvas.GetTop(target); 

     DoubleAnimation anim1 = new DoubleAnimation(oldP.X, newP.X, TimeSpan.FromSeconds(0.2)); 
     DoubleAnimation anim2 = new DoubleAnimation(oldP.Y, newP.Y , TimeSpan.FromSeconds(0.2)); 

     target.BeginAnimation(Canvas.LeftProperty , anim1); 
     target.BeginAnimation(Canvas.TopProperty, anim2); 

    } 
1

seguía teniendo NaN o valores 0 para mis elementos anidados, aquí está una versión modificada de la respuesta de Danny:

public void MoveTo(Canvas canvas, FrameworkElement target, FrameworkElement destination) 
    { 
     Point oldPoint = target.TransformToAncestor(canvas).Transform(new Point(0, 0)); 
     Point newPoint = destination.TransformToAncestor(canvas).Transform(new Point(0, 0)); 

     var EndX = destination.Width/2 + newPoint.X - oldPoint.X - (target.Width/2); 
     var EndY = destination.Height/2 + newPoint.Y - oldPoint.Y - (target.Height/2); 

     TranslateTransform trans = new TranslateTransform(); 
     target.RenderTransform = trans; 
     DoubleAnimation anim1 = new DoubleAnimation(0, EndX, TimeSpan.FromSeconds(0.3)); 
     DoubleAnimation anim2 = new DoubleAnimation(0, EndY, TimeSpan.FromSeconds(0.3)); 
     trans.BeginAnimation(TranslateTransform.XProperty, anim1); 
     trans.BeginAnimation(TranslateTransform.YProperty, anim2); 
    } 
Cuestiones relacionadas