2015-10-07 33 views
13

我有这应该在屏幕上移动图像的方法运行狗类:运行方法同时

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; 
} 

这种方法是,其中4个狗对象创建一个按钮单击事件和被叫每个对象调用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(); 
} 

的问题是,每一种方法执行一个接一个,不能同时。我希望每个方法同时运行。如果我删除了while语句,那么所有的方法都会同时执行,但是在while循环中,它们会一个接一个地执行。有关如何解决这个问题的任何建议,非常感谢。而不while循环运行方法:

public bool Run() //Dog1.Run() 
{ 
    Point p = PictureBoxDog.Location; 

    int movement = Randomizer.Next(0, 30); 
    //Location += movement; 

    p.X += movement; 
    PictureBoxDog.Location = p; 

    if (Location == 4) //Incomplete code. 
    return true; 
    else 
    return false; 
} 
+2

添加一个计时器并从那里调用方法。那么,如果你不知道自己在做什么,那么你就不必乱用线程,这会导致UI元素出现问题。 –

回答

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

这并不解决while循环问题。 –

+0

它说我需要一个对象引用来使用分派器。我应该做些什么?对不起,我对这个东西不是很有经验。 – grammer

+1

问题涉及PictureBoxes,这是WinForms。你在谈论Dispatcher,这是WPF - 我怀疑它会在WinForms事件循环中发挥作用。 –

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(); 
     }); 
    } 

} 

然后你的狗类看起来像这样。它需要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; 
    } 
} 
+0

像这种方法一样,但我会重新使用'Random'实例并使用表单/图片框上的'BeginInvoke'分配绘图调用。 – Gene

+0

好皮卡!谢谢! –

+0

感谢您的帮助,但这对我来说似乎太过先进。我无法真正理解它。我对C#不是很有经验。 – grammer

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));} 
+0

这导致了错误。 – grammer

+0

我编辑了答案 – Donald

+0

试过了。它导致另一个错误消息:附加信息:跨线程操作无效:控制'pictureDog4'从其他线程创建的控件上执行跨线程操作时,从 – grammer