Windows窗体应用程序中的线程交叉

时间:2010-02-16 07:50:43

标签: c# multithreading

我在我的应用程序中使用了两个线程(WindowsForms)。用于获取客户端的ThumbnailImages的另一个线程和用于获取客户端的全尺寸图像的另一个线程...其工作但不正确...当我单击缩略图图像按钮时它正确地给出缩略图图像之后我单击该全尺寸图像按钮,它来了作为全尺寸图像和缩略图图像...然后返回缩略图图像按钮它作为缩略图和Fullsize图像也来了....

两条线正在交叉,为什么我没有得到正确的输出......

我如何解决这个问题?告诉我解决方案......

这是我的代码......

{
    System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;
    th = new Thread(new ThreadStart(startlooping));
    th.Start();
}

void StartLooping()
{
    localconnection();

    for (int i = 0; i < Num_Picbox; i++)
    {
        clsImage pcimg = frmDisplay.Serviceobj.ConnectToPcAndGetImage(listBox1.Items[i].ToString(), imgid);

        Image img = objConvertByteToStream.byteArrayToImage(pcimg.pcimage);

        if (listBox1.Items[i].ToString() == pcimg.IPadd && imgid == 0)
        {
            shapes[i].Image = img;
        }

        pcimg = null;
    }
}

private void PictureBox_Click(object sender, EventArgs e)
{
    pb= sender as PictureBox;

    System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;

    thread = new Thread(new ThreadStart(GetImage));

    thread.Start();
}

void GetImage()
{
    pictureBox1.Visible = true;
    btnBack.Visible = true;

    pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;

    label1.Visible = true;
    pictureBox1.Height = this.flowLayoutPanel1.Height;
    pictureBox1.Width = this.flowLayoutPanel1.Width;

    btnGetConnectedPcs.Location = new Point(168, 616);

    btnGetImageFromSelectedPc.Location = new Point(352, 616);

    for (; ; )
    {
        count++;
        int imageid = 1;
        localconnection();

        string strIpaddress = listBox1.Items[Convert.ToInt32(pb.Name)].ToString();
        .........................
        .........................
    }
}

3 个答案:

答案 0 :(得分:3)

请勿使用CheckForIllegalCrossThreads并对您正在使用的控件使用Invoke。

答案 1 :(得分:1)

我认为你应该使用BackgroundWorker。不要使用CheckForIllegalCrossThreadCalls;这是有原因的。

它处理“编组”(在一个线程上调用以切换到另一个线程以进行UI更新)。

这是一个很好的首发:http://bigballofmud.wordpress.com/2009/03/28/thread-marshalling-part-2-using-backgroundworker/

此外,您需要在其他线程运行时控制UI。通常通过禁用按钮/菜单等来防止用户要求更多像已经运行的东西。

至少你应该使用Control.Invoke。当你的线程完成下载图像时,它应该调用一个方法来显示它们。然后,该方法应该检查this.InvokeRequired,如果是,则应通过this.Invokethis.BeginInvoke调用自己。这将有效切换回主UI线程,避免您可能看到的错误。

Plz给我发送codez?

好的,这次你可以多一点,但你还需要掌握一些方向的技巧然后找到自己的方式。如果我们帮助您解决此问题的实际代码,那么下次遇到问题时您就会回来。我们宁愿让你像一个发条玩具一样,而不是像遥控车一样引导你:)

BackgroundWorker的

我将为您推荐BackgroundWorker article on MSDN

BackgroundWorker是您从工具箱中删除表单的组件。它不像文本框那样是视觉控制,而是更像是计时器或工具提示。

以最简单的形式使用它意味着订阅DoWorkRunWorkerCompleted事件,如MSDN文章中所述。如果要进行某些下载,则需要执行以下操作:

  • 禁用您的用户界面(以防止后续按下按钮)。
  • 设置某种进度/工作动画或消息。
  • 调用BackgroundWorker.RunWorkerAsync,传入一个包含参数的对象,告诉它该做什么(即下载大图像或小图像)。

您的案例中的DoWork事件将被引发,您的方法将在与UI不同的线程中运行,因此您不允许在此方法中更新UI。编写DoWork方法以下载图像,并在下载完成后将DoWorkEventArgs.Result属性设置为该图像集。

DoWork方法完成时,BackgroundWorker将触发RunWorkerCompleted事件,并且将调用您订阅它的方法。此代码现在将再次在UI线程上自动运行,因此您应该执行以下操作:

  • 报告RunWorkerCompletedEventArgs.Error属性中的任何错误(实际上这是DoWork方法中发生的任何未捕获的错误。请在此处理它们,以便您可以使用UI通知用户该问题)。
  • 创建控件以显示RunWorkerCompletedEventArgs.
  • 中包含的图像
  • 隐藏任何进度指示器。
  • 重新启用您的UI(最好使用finally块,以便任何异常都不会导致您的UI被永久和无法挽回地锁定)。

答案 2 :(得分:0)

您可能需要快速查看Control.InvokeRequired()。这可能会有所启发,并为你提供一条通往成功的明确途径。

祝你好运。