Error:The calling thread cannot access this object because a different thread owns it. Storyboard simulation
Error:The calling thread cannot access this object because a different thread owns it. Storyboard simulation
对于我的学校项目,我正在尝试射弹模拟,但决定使用故事板(不确定这是否正确),所以到目前为止我的代码是这样的。正如您从标题中看到的那样,我在尝试执行时遇到了该错误
ellipseStoryboard.Begin(这个);
但我看不出我做错了什么。感谢您的帮助!
我的代码:
void onTimedEvent(Object sender, ElapsedEventArgs t, particle newProjectile, double TimeInterval, int i, Path myPath, Canvas AnimationCanvas)
{
this.Dispatcher.Invoke((Action)(() =>
{
AnimationCanvas.Children.Clear();
}));
PointAnimation myPointAnimation = new PointAnimation();
myPointAnimation.Duration = TimeSpan.FromSeconds(TimeInterval);
myPointAnimation.RepeatBehavior = new RepeatBehavior(1);
myPointAnimation.From = new System.Windows.Point(newProjectile.HDisplacement[i], newProjectile.VDisplacement[i]);
myPointAnimation.To = new System.Windows.Point(newProjectile.HDisplacement[i + 1], newProjectile.VDisplacement[i + 1]);
Storyboard.SetTargetName(myPointAnimation, "MyAnimatedEllipseGeometry");
Storyboard.SetTargetProperty(myPointAnimation, new PropertyPath(EllipseGeometry.CenterProperty));
Storyboard ellipseStoryboard = new Storyboard();
ellipseStoryboard.Children.Add(myPointAnimation);
this.Dispatcher.Invoke((Action)(() =>
{
myPath.Loaded += delegate(object sender1, RoutedEventArgs e)
{
ellipseStoryboard.Begin(this);
};
}));
this.Dispatcher.Invoke((Action)(() =>
{
AnimationCanvas.Children.Add(myPath);
}));
}
编辑:实际位移点我算出来了,放在一个数组里
您可能不需要更多:
myPath.Loaded +=
(o, e) =>
{
var myPointAnimation = new PointAnimation
{
Duration = TimeSpan.FromSeconds(TimeInterval),
From = new Point(...),
To = new Point(...)
};
MyAnimatedEllipseGeometry.BeginAnimation(
EllipseGeometry.CenterProperty, myPointAnimation);
};
虽然射弹的 x 和 y 坐标的独立动画(例如,通过情节提要中的两个动画)和 y 坐标的二次缓动函数可以模拟重力,但您最好使用 frame-based animation 用于具有时间相关运动学的真实物理模拟。
上面的简单版本可能如下所示:
<Path Fill="Black">
<Path.Data>
<EllipseGeometry x:Name="projectileGeometry" RadiusX="5" RadiusY="5"/>
</Path.Data>
</Path>
使用以下代码隐藏,其中有弹丸的位置、速度和加速度,以及计算运动学的 Rendering
事件处理程序。
private Point position; // in pixels
private Vector velocity; // in pixels per second
private Vector acceleration; // in pixels per square second
private DateTime time;
public MainWindow()
{
InitializeComponent();
Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
position = new Point(100, 100);
velocity = new Vector(50, -50); // y direction is downwards
acceleration = new Vector(0, 20); // y direction is downwards
time = DateTime.Now;
CompositionTarget.Rendering += OnRendering;
}
private void OnRendering(object sender, EventArgs e)
{
var t = DateTime.Now;
var dt = (t - time).TotalSeconds;
time = t;
position += velocity * dt;
velocity += acceleration * dt;
projectileGeometry.Center = position;
if (position.Y > ActualHeight)
{
CompositionTarget.Rendering -= OnRendering;
}
}
您似乎正试图通过计时器启动动画。如果您收到线程错误,则您可能在错误的线程上。不要使用 Dispatcher.Invoke
编组,只需使用 DispatcherTimer
即可确保您的回调在 UI 线程上。
而不是:
var timer = new System.Timers.Timer(1000);
timer.Elapsed += tmrHandler;
timer.Enabled = true;
使用
var timer = new DispatcherTimer(DispatcherPriority.Normal);
timer.Interval = TimeSpan.FromSeconds(1);
timer.Tick += tmrHandler;
timer.IsEnabled = true;
对于我的学校项目,我正在尝试射弹模拟,但决定使用故事板(不确定这是否正确),所以到目前为止我的代码是这样的。正如您从标题中看到的那样,我在尝试执行时遇到了该错误 ellipseStoryboard.Begin(这个); 但我看不出我做错了什么。感谢您的帮助!
我的代码:
void onTimedEvent(Object sender, ElapsedEventArgs t, particle newProjectile, double TimeInterval, int i, Path myPath, Canvas AnimationCanvas)
{
this.Dispatcher.Invoke((Action)(() =>
{
AnimationCanvas.Children.Clear();
}));
PointAnimation myPointAnimation = new PointAnimation();
myPointAnimation.Duration = TimeSpan.FromSeconds(TimeInterval);
myPointAnimation.RepeatBehavior = new RepeatBehavior(1);
myPointAnimation.From = new System.Windows.Point(newProjectile.HDisplacement[i], newProjectile.VDisplacement[i]);
myPointAnimation.To = new System.Windows.Point(newProjectile.HDisplacement[i + 1], newProjectile.VDisplacement[i + 1]);
Storyboard.SetTargetName(myPointAnimation, "MyAnimatedEllipseGeometry");
Storyboard.SetTargetProperty(myPointAnimation, new PropertyPath(EllipseGeometry.CenterProperty));
Storyboard ellipseStoryboard = new Storyboard();
ellipseStoryboard.Children.Add(myPointAnimation);
this.Dispatcher.Invoke((Action)(() =>
{
myPath.Loaded += delegate(object sender1, RoutedEventArgs e)
{
ellipseStoryboard.Begin(this);
};
}));
this.Dispatcher.Invoke((Action)(() =>
{
AnimationCanvas.Children.Add(myPath);
}));
}
编辑:实际位移点我算出来了,放在一个数组里
您可能不需要更多:
myPath.Loaded +=
(o, e) =>
{
var myPointAnimation = new PointAnimation
{
Duration = TimeSpan.FromSeconds(TimeInterval),
From = new Point(...),
To = new Point(...)
};
MyAnimatedEllipseGeometry.BeginAnimation(
EllipseGeometry.CenterProperty, myPointAnimation);
};
虽然射弹的 x 和 y 坐标的独立动画(例如,通过情节提要中的两个动画)和 y 坐标的二次缓动函数可以模拟重力,但您最好使用 frame-based animation 用于具有时间相关运动学的真实物理模拟。
上面的简单版本可能如下所示:
<Path Fill="Black">
<Path.Data>
<EllipseGeometry x:Name="projectileGeometry" RadiusX="5" RadiusY="5"/>
</Path.Data>
</Path>
使用以下代码隐藏,其中有弹丸的位置、速度和加速度,以及计算运动学的 Rendering
事件处理程序。
private Point position; // in pixels
private Vector velocity; // in pixels per second
private Vector acceleration; // in pixels per square second
private DateTime time;
public MainWindow()
{
InitializeComponent();
Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
position = new Point(100, 100);
velocity = new Vector(50, -50); // y direction is downwards
acceleration = new Vector(0, 20); // y direction is downwards
time = DateTime.Now;
CompositionTarget.Rendering += OnRendering;
}
private void OnRendering(object sender, EventArgs e)
{
var t = DateTime.Now;
var dt = (t - time).TotalSeconds;
time = t;
position += velocity * dt;
velocity += acceleration * dt;
projectileGeometry.Center = position;
if (position.Y > ActualHeight)
{
CompositionTarget.Rendering -= OnRendering;
}
}
您似乎正试图通过计时器启动动画。如果您收到线程错误,则您可能在错误的线程上。不要使用 Dispatcher.Invoke
编组,只需使用 DispatcherTimer
即可确保您的回调在 UI 线程上。
而不是:
var timer = new System.Timers.Timer(1000);
timer.Elapsed += tmrHandler;
timer.Enabled = true;
使用
var timer = new DispatcherTimer(DispatcherPriority.Normal);
timer.Interval = TimeSpan.FromSeconds(1);
timer.Tick += tmrHandler;
timer.IsEnabled = true;