我有一个带有方法Run的Dog类,它应该在屏幕上移动图片:
let
从按钮单击事件调用此方法,其中创建了4个狗对象,并且每个对象都调用Run方法:
public bool Run()
{
Point p = PictureBoxDog.Location;
while(p.X < 530)
{
int movement = Randomizer.Next(0, 3);
p.X += movement;
PictureBoxDog.Location = p;
}
if (Location == 4) //Incomplete section.
return true;
else
return false;
}
问题是每个方法一个接一个地执行,而不是同时执行。我希望每个方法同时运行。如果我删除了while语句,那么所有方法都会同时执行,但是使用while循环,它们会一个接一个地执行。任何关于如何解决这个问题的建议都非常感谢。没有while循环的run方法:
private void button1_Click(object sender, EventArgs e)
{
Dog dog1 = new Dog(pictureDog1);
Dog dog2 = new Dog(pictureDog2);
Dog dog3 = new Dog(pictureDog3);
Dog dog4 = new Dog(pictureDog4);
dog1.Run();
dog2.Run();
dog3.Run();
dog4.Run();
}
答案 0 :(得分:13)
动画和WinForms通常并不简单。程序员通常做的是建立一个游戏循环。游戏循环执行三项操作 - 获取用户输入,更新精灵的新位置,然后在屏幕上绘制精灵。
using System.Threading;
public partial class Form1
{
private Timer _timer;
private Dog _dog1, _dog2, _dog3, _dog4;
public void InitializeComponent()
{
SetupDogs();
// Every quarter of a second, run the function GameLoop
_timer = new Timer(GameLoop, null,
TimeSpan.FromSeconds(0.25),
TimeSpan.FromSeconds(0.25));
}
private void SetupDogs()
{
_dog1 = new Dog(PictureBoxDog1);
_dog2 = new Dog(PictureBoxDog2);
_dog3 = new Dog(PictureBoxDog3);
_dog4 = new Dog(PictureBoxDog4);
}
public void GameLoop(object state)
{
GetUserInput();
Update();
Draw();
}
public void GetUserInput()
{
// You don't need this now. But if you need to
// process user input later, you can do it here.
//
// e.g. if Last key
// pressed was arrow-left or
// arrow-right etc.
}
public void Update()
{
_dog1.Update();
_dog2.Update();
_dog3.Update();
_dog4.Update();
}
public void Draw()
{
// Draw on the main UI thread
Dispatcher.BeginInvoke(() =>
{
_dog1.Draw();
_dog2.Draw();
_dog3.Draw();
_dog4.Draw();
});
}
}
然后你的Dog课程看起来像这样。每次计时器滴答时,它需要Update
其位置,然后绘制其位置:
public class Dog
{
bool _isRunning = true;
Point Location { get; set; }
Point NextLocation { get; set; }
PictureBox PictureBoxDog { get; set; }
public Dog(PictureBox pictureBox)
{
PictureBoxDog = pictureBox;
Location = GetRandomLocation();
NextLocation = GetRandomLocation();
}
private Point GetRandomLocation()
{
var random = new Random();
return new Point(random.Next(800), random.Next(800));
}
public void Update()
{
// Calculates the new coordinates for a dog
// The dog starts from a random position, and is
// given a new random position to run towards.
// If the dog has arrived at the new random position, then
// give the dog a new random position to run to again
if (NextLocation.X == Location.X && NextLocation.Y == Location.Y)
{
NextLocation = GetRandomLocation();
}
if (_isRunning)
{
// Move the dog closer to its destination
// dx and dy can be -1, 0, or 1
var dx = Math.Sign(NextLocation.X - Location.X);
var dy = Math.Sign(NextLocation.Y - Location.Y);
Location = new Point(Location.X + dx, Location.Y + dy);
}
}
public void Draw()
{
PictureBoxDog.Location = Location;
}
}
答案 1 :(得分:4)
试试这个
Dispatcher.BeginInvoke((Action) (() =>
{
dog1.Run();
}));
Dispatcher.BeginInvoke((Action) (() =>
{
dog2.Run();
}));
Dispatcher.BeginInvoke((Action) (() =>
{
dog3.Run();
}));
Dispatcher.BeginInvoke((Action) (() =>
{
dog4.Run();
}));
和While循环也使用此
Dispatcher.BeginInvoke((Action) (() =>
{
while(p.X < 530)
{
int movement = Randomizer.Next(0, 3);
p.X += movement;
PictureBoxDog.Location = p;
}
}));
BeginInvoke是异步的;因此,控制在调用后立即返回调用对象。 BeginInvoke返回一个DispatcherOperation对象,当委托在事件队列中时,该对象可用于与委托进行交互。 BeginInvoke返回的DispatcherOperation对象可以通过多种方式与指定的委托进行交互
答案 2 :(得分:0)
为什么不尝试这个?
Task.Factory.StartNew( () => Parallel.ForEach<Dog>(Dogs, dog=> dog.run()));
要正确使用此指令,您应该创建一个Dog列表。
List<Dog> Dogs = new List<Dog>();
Dogs.Add(dog1);
Dogs.Add(dog2);
Dogs.Add(dog3);
Dogs.Add(dog4);
Task.Factory.StartNew(() => Parallel.ForEach<Dog>(Dogs, dog => dog.Run()));
如果您不喜欢列表:
Task.Factory.StartNew(() => dog1.Run());
Task.Factory.StartNew(() => dog2.Run());
Task.Factory.StartNew(() => dog3.Run());
Task.Factory.StartNew(() => dog4.Run());
要从不同的线程与UI进行交互,您需要使用委托并调用Control.Invoke / BeginInvoke。 您可以使用InvokeRequired属性测试是否需要调用Invoke。 所以在你的情况下:
if (PictureBoxDog.InvokeRequired){
PictureBoxDog.Invoke((MethodInvoker)(() => PictureBoxDog.location = p));}