В вашем коде много неправильных вещей, и самое важное, что ваши обработчики тиков никогда не сравнивают фактическое значение Left или Top с какими-либо границами.
Попробуйте эту упрощенную версию:
<Window ... KeyDown="WindowKeyDown">
<Grid>
<Canvas x:Name="canvas" Margin="40">
<Ellipse x:Name="ellipse" Canvas.Left="300" Canvas.Top="200"
Width="75" Height="75" Margin="-37.5" Fill="Black"/>
</Canvas>
</Grid>
</Window>
с кодом только с одним таймером и обработчиком Tick, который обновляет Left
и Top
в соответствии с вектором скорости.Новая позиция проверяется относительно нижней границы нуля и верхней границы canvas.ActualWidth
/ canvas.ActualHeight
.
public partial class MainWindow : Window
{
private Vector speed = new Vector();
public MainWindow()
{
InitializeComponent();
var timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(20) };
timer.Tick += TimerTick;
timer.Start();
}
private void TimerTick(object sender, EventArgs e)
{
var pos = new Point(Canvas.GetLeft(ellipse), Canvas.GetTop(ellipse)) + speed;
Canvas.SetLeft(ellipse, Math.Min(Math.Max(pos.X, 0), canvas.ActualWidth));
Canvas.SetTop(ellipse, Math.Min(Math.Max(pos.Y, 0), canvas.ActualHeight));
}
private void WindowKeyDown(object sender, KeyEventArgs e)
{
speed.X = 0;
speed.Y = 0;
switch (e.Key)
{
case Key.Left:
speed.X = -10;
break;
case Key.Right:
speed.X = 10;
break;
case Key.Up:
speed.Y = -10;
break;
case Key.Down:
speed.Y = 10;
break;
}
}
}
Теперь вы можете также реализовать другую стратегию перемещения, добавляя или вычитая компоненты из / из текущеговектор скорости:
private void WindowKeyDown(object sender, KeyEventArgs e)
{
switch (e.Key)
{
case Key.Left:
speed.X--;
break;
case Key.Right:
speed.X++;
break;
case Key.Up:
speed.Y--;
break;
case Key.Down:
speed.Y++;
break;
default:
speed.X = 0;
speed.Y = 0;
break;
}