2010-11-04 15 views
5

estoy haciendo una aplicación Wpf y creo un control con la forma de un ojo, puse una elipse (ojo) en un lienzo y mi propósito es cuando el cursor del mouse entre en el lienzo, la elipse sigue el cursor del mouse. ¿Tiene alguna sugerencia sobre cómo realizar esta tarea? Muchas gracias por su atención.Objeto siguiendo el cursor del mouse

Saludos

EDIT

Tengo actualizar mi código en XAML:

<Window Height="480" Title="Window2" Width="640" x:Class="WpfApplication5.Window2" 
    x:Name="Window" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 
    <Window.Resources> 
    <Storyboard x:Key="OnLoaded1"> 
     <DoubleAnimationUsingKeyFrames Storyboard.TargetName="ctrCircle" 
     Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)"> 
     <EasingDoubleKeyFrame KeyTime="0:0:0.8" Value="1"> 
      <EasingDoubleKeyFrame.EasingFunction> 
      <ExponentialEase EasingMode="EaseOut" /> 
      </EasingDoubleKeyFrame.EasingFunction> 
     </EasingDoubleKeyFrame> 
     </DoubleAnimationUsingKeyFrames> 
     <DoubleAnimationUsingKeyFrames Storyboard.TargetName="ctrCircle" 
      Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)"> 
     <EasingDoubleKeyFrame KeyTime="0:0:0.8" Value="1"> 
     <EasingDoubleKeyFrame.EasingFunction> 
      <ExponentialEase EasingMode="EaseOut" /> 
      </EasingDoubleKeyFrame.EasingFunction> 
     </EasingDoubleKeyFrame> 
     </DoubleAnimationUsingKeyFrames> 
    </Storyboard> 
    <Style TargetType="Ellipse"> 
     <Setter Property="RenderTransform"> 
     <Setter.Value> 
      <ScaleTransform ScaleX="1" ScaleY="1"/> 
     </Setter.Value> 
     </Setter> 
     <Setter Property="RenderTransformOrigin" Value="0.5,0.5"/> 
    </Style> 
    </Window.Resources> 

    <Canvas MouseMove="mov" x:Name="LayoutRoot"> 
    <Border ackground="Black" B="" Canvas.Left="178" Canvas.Top="103" 
     CornerRadius="250" Height="255.5" Width="290" x:Name="border_eye"> 
     <Ellipse Fill="#FFFFC600" Height="12" HorizontalAlignment="Left" 
     Margin="0" RenderTransformOrigin="0.5,0.5" Stroke="{x:Null}" 
     VerticalAlignment="Center" Visibility="Visible" Width="12" x:Name="ctrCircle"> 
     <Ellipse.RenderTransform> 
      <TransformGroup> 
      <ScaleTransform /> 
      <SkewTransform /> 
      <RotateTransform /> 
      <TranslateTransform />     
      </TransformGroup> 
     </Ellipse.RenderTransform> 
     </Ellipse> 
    </Border> 
    </Canvas> 
</Window> 

y en el código detrás:

private void mov(object sender, MouseEventArgs e) 
    { 
System.Windows.Point pt = e.GetPosition((Canvas)sender); 
     Storyboard invokeStoryboard = this.Resources["OnLoaded1"] as Storyboard; 
     ((DoubleAnimationUsingKeyFrames)invokeStoryboard.Children[0]).KeyFrames[0].Value = pt.X; 
     ((DoubleAnimationUsingKeyFrames)invokeStoryboard.Children[1]).KeyFrames[0].Value = pt.Y; 
     invokeStoryboard.Begin(); 
    } 

ahora mi propósito es cuando muevo el mouse en el área de Canvas (LayoutRoot), el Ellipse (ctrCircle) solo se mueve dentro del borde (border_eye) y no supere el área de "border_eye", este efecto es similar a un ojo.

¿Tiene alguna entrada para resolver este paso?

Gracias tanto

tengas un buen día.

Saludos

Respuesta

7

Aquí hay un ejemplo de cómo hacer un ojo en un lienzo de WPF usando el Rx framework. El uso de Rx en lugar de adjuntar al evento de movimiento del mouse directamente le permite almacenar en búfer los eventos y solo actualizar la posición del alumno cada 10 milisegundos, reduciendo la carga general de la CPU.

El Xaml

<UserControl 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    mc:Ignorable="d" 
    x:Class="namespace.EyeDemo" 
    x:Name="UserControl" 
    d:DesignWidth="640" d:DesignHeight="480"> 

    <Canvas x:Name="LayoutRoot" Background="GreenYellow"> 
     <Ellipse Fill="Black" Width="120" Height="70" Canvas.Left="90" Canvas.Top="115"/> 
     <Ellipse x:Name="Eye" Fill="Black" Width="100" Height="50" Canvas.Left="100" Canvas.Top="125"/> 
     <Ellipse x:Name="Pupil" Fill="Red" Height="20" Canvas.Left="139" Canvas.Top="138" Width="20"/> 
    </Canvas> 
</UserControl> 

y el código detrás

/// <summary> 
/// Interaction logic for EyeDemo.xaml 
/// </summary> 
public partial class EyeDemo : UserControl 
{ 
    public EyeDemo() 
    { 
     this.InitializeComponent(); 

     double majorRadius = Eye.Width/2d; 
     double minorRadius = Eye.Height/2d; 
     Point center = new Point(Canvas.GetLeft(Eye) + majorRadius, Canvas.GetTop(Eye) + minorRadius); 

     // create event streams for mouse down/up/move using reflection 
     // to keep taking mouse move events and return the X, Y positions 
     var mouseMove = from evt in Observable.FromEvent<MouseEventArgs>(LayoutRoot, "PreviewMouseMove") 
         select (Point?)evt.EventArgs.GetPosition(this); 

     // subscribe to the stream of position changes and modify the Canvas.Left and Canvas.Top 
     // use the bound by elipse function to restrain the pupil to with the eye. 
     mouseMove.BufferWithTime(TimeSpan.FromMilliseconds(10)).Select(p => BoundByElipse(majorRadius, minorRadius, center, p.LastOrDefault())) 
      .ObserveOnDispatcher().Subscribe(pos => 
       { 
        if(pos.HasValue) 
        { 
         Canvas.SetLeft(Pupil, pos.Value.X - Pupil.Width/2d); 
         Canvas.SetTop(Pupil, pos.Value.Y - Pupil.Height/2d); 
        } 
       }); 
    } 

    private Point? BoundByElipse(double majorRadius, double minorRadius, Point center, Point? point) 
    { 
     if(point.HasValue) 
     { 
      // Formular for an elipse is x^2/a^2 + y^2/b^2 = 1 
      // where a = majorRadius and b = minorRadius 
      // Using this formular we can work out if the point is with in the elipse 
      // or find the boundry point closest to the point 

      // Find the location of the point relative to the center. 
      Point p = new Point(point.Value.X - center.X, point.Value.Y - center.Y); 
      double a = majorRadius; 
      double b = minorRadius; 

      double f = p.X * p.X/(a * a) + p.Y * p.Y/(b * b); 
      if(f <= 1) 
      { 
       // the point is with in the elipse; 
       return point; 
      } 
      else 
      { 
       // the point is outside the elipse, therefore need to find the closest location on the boundry. 
       double xdirection = point.Value.X > center.X ? 1 : -1; 
       double ydirection = point.Value.X > center.X ? 1 : -1; 

       double r = p.X/p.Y; 

       double x = p.Y != 0 ? Math.Sqrt(r * r * a * a * b * b/(r * r * b * b + a * a)) : a; 
       double y = r != 0 ? x/r : (point.Value.Y > center.Y ? -b : b); 

       return new Point(center.X + xdirection * x, center.Y + ydirection * y); 
      } 
     } 
     else 
     { 
      return null; 
     } 
    } 
} 
3

Uso MouseMove y asegurarse de que el lienzo tiene un fondo para la prueba de posicionamiento.

XAML:

<Canvas MouseMove="Canvas_MouseMove" 
     Background="Transparent"> 
    <Ellipse x:Name="eye" 
      Width="50" 
      Height="20" 
      Fill="Blue" /> 
</Canvas> 

Codebehind:

private void Canvas_MouseMove(object sender, System.Windows.Input.MouseEventArgs e) 
{ 
    var pos = e.GetPosition((Canvas)sender); 
    Canvas.SetLeft(eye, pos.X); 
    Canvas.SetTop(eye, pos.Y); 
} 
+0

Gracias Chris me olvidé de anotar un detalle, la estancia ojo en otro componente anoto el código: ... así que cuando el mouse ingrese en mainCanvas, el ojo se moverá dentro del canvas_eye sin salir del borde de canvas_eye.Lo siento por mi mala explicación antes, espero que entiendas el objetivo de mi tarea. – JayJay

+0

Parece que JayJay también quiere un retraso de aceleración de 8 segundos, definido en XAML. – bitbonk

1

La forma en que lo hizo es casi correcta, excepto que no se puede modificar las propiedades de una animación después de que se utiliza la animación. Tienes que crear una nueva animación usando Clone() y modificarla, eliminar la animación anterior y luego aplicar la nueva animación.

Cuestiones relacionadas