如何运行while(true)循环而不冻结C#中的Windows窗体?

时间:2014-11-19 09:57:20

标签: c# kinect

我正在编写一个应用程序,该应用程序应显示最多4个Kinect的跟踪骨架。当用户按下Start按钮时,应该开始跟踪然后在表单上绘图。来自Java背景我对在C#中使用delegatesEventHandlers知之甚少。到目前为止,我的代码看起来像这样,但它完全冻结了表单。如何解决?

private void MainWindow_Load(object sender, EventArgs e)
{
    ProgramLoop();
}

private void ProgramLoop()
{
    int sensorCount = 0;
    foreach (KinectSensor connectedSensor in KinectSensor.KinectSensors)
    {
        if (connectedSensor.Status == KinectStatus.Connected)
        {
            connectedSensor.SkeletonStream.Enable();
            connectedSensorsArray.Add(connectedSensor);
            connectedSensor.Start();
            sensorCount++;
        }
    }
}

private void start_Click(object sender, EventArgs e)
{
    trackSkeletons();
}

private void trackSkeletons()
{
    while (true)
    {
        foreach (KinectSensor sensor in connectedSensorsArray)
        {
            SkeletonFrame skeletonFrame = sensor.SkeletonStream.OpenNextFrame(200);
            if (skeletonFrame != null)
            {
                if (initSkeletons == null)
                {
                    initSkeletons = new Skeleton[skeletonFrame.SkeletonArrayLength];
                }
                skeletonFrame.CopySkeletonDataTo(initSkeletons);
                skeletonFrame.Dispose();
                Skeleton initSkeleton = initSkeletons.Where(s => s.TrackingState == SkeletonTrackingState.Tracked).FirstOrDefault();
                if (initSkeleton != null)
                {
                    switch (connectedSensorsArray.IndexOf(sensor))
                    {
                        case 0:
                            mainQueue.Enqueue(initSkeleton);
                            break;
                        case 1:
                            secondQueue.Enqueue(initSkeleton);
                            break;
                        case 2:
                            thirdQueue.Enqueue(initSkeleton);
                            break;
                        case 3:
                            fourthQueue.Enqueue(initSkeleton);
                            break;
                    }
                }
            }
        }
        //dequeue Skeletons and draw them
    }
}

4 个答案:

答案 0 :(得分:1)

你应该使用计时器而不是while(true)

您的计时器将每隔X秒执行一次,当他被召唤时,您可以调用自己的函数trackSkeletons()

答案 1 :(得分:0)

正如我所说你需要使用线程,我不知道kinect sdk是如何工作的,但只要trackSkeletons()不会写入另一个线程正在使用的数据,它就应该很好,否则你需要解决这个问题某种同步。但我认为它应该像这样工作

private void start_Click(object sender, EventArgs e)
{
    Thread thread = new Thread(trackSkeletons);
    thread.Start();
}

在trackSkeletons中你可以在一段时间内(但仍在其中)添加一段时间的睡眠

while(true)
{
    //code
    Thread.Sleep(50);
}

答案 2 :(得分:0)

首先,我认为您需要休息条件来停止跟踪。

如果您不想冻结UI,也需要使用线程。

对于线程来说非常简单:

Thread t = new Thread(trackSkeletons);
t.Start();

现在在您的课程中,您应该添加一个私有布尔字段_trackSkeletons,以便您的点击事件如下所示:

Thread t = new Thread(trackSkeletons);
_trackSkeletons = true;
t.Start();

在trackSkeletons方法中,使用:

while(_trackSkeletons)
{
   ....
}

这使您可以在需要时停止线程(可能通过单击“停止”按钮)。 Vajura建议的Thread.Sleep方法也很有用。

在Winform应用程序中使用线程时要知道的最后一件事是:您不能直接从线程更改任何用户界面元素,否则您将获得异常。您需要使用Invoke方法来执行此操作。

答案 3 :(得分:0)

使用像这样的需要线程;

 private void start_Click(object sender, EventArgs e)
    {
       Thread t = new Thread(trackSkeletons);
    t.Start();
    }

帮助:Threads