c#线程和显示更新

时间:2009-02-19 19:09:00

标签: c# winforms multithreading

我有一个带有标签和图片框的Windows窗体。要从Web服务中检索图像,我使用一个线程。

用户单击按钮,首先必须显示标签,然后启动新线程以检索图像。这是代码:

private void menuItem1_Click(object sender, EventArgs e)

{

etiquetaCargando.Visible = true;

this.Invoke(new System.Threading.ThreadStart(RequestImage));

}

问题在于:标签etiquetaCargando没有出现。

我在Compact Framework上编程。

发生了什么事?

谢谢!

4 个答案:

答案 0 :(得分:3)

问题不明确,但是通过使用Invoke,您正在破坏在单独的线程上提供图像请求的目的。 (您可能会注意到在请求发生时您的界面没有响应)

相反,最好创建一个新的线程对象,启动它,然后使用Invoke来设置图像(在检索之后),这是

的内容。
private void menuItem1_Click(object sender, EventArgs e)
{    
    etiquetaCargando.Visible = true;
    Thread reqThread =
        new Thread(new ThreadStart(RequestImage));
    reqThread.Start();
}

private void RequestImage()
{
    /* Get the image
    ...
    */
    Invoke(SetTheImage, new object[] { theImage });
}

这假设您有一个方法SetTheImage,它实际上将在您的表单上显示图像。

答案 1 :(得分:3)

你不应该这样称呼:

this.Invoke(new System.Threading.ThreadStart(RequestImage));

我假设你在这里遇到死锁,因为Invoke方法会将委托路由到UI线程,但你正在等待你的操作完成。

要使代码在另一个线程上执行,您可以这样做:

private void menuItem1_Click(object sender, EventArgs e)
{
    etiquetaCargando.Visible = true;

    Thread t = new Thread(RequestImage);

    t.Start();
}

然后,在RequestImage方法中,您将调用Invoke方法,传递一个委托以在UI线程上执行,在这种情况下,传递您下载的图像。

答案 2 :(得分:0)

您可以执行以下操作:

private void menuItem1_Click(object sender, EventArgs e)
{
    etiquetaCargando.Visible = true;
    Thread t = new Thread(new ThreadStart(RequestImage));

    // NOTE THIS LINE
    // Without this, if your application is closed and the thread isn't,
    // it will leave your program in memory until it does
    t.IsBackground = true;

    this.Invoke(new System.Threading.ThreadStart(RequestImage));
}

private void RequestImage() 
{
    // Do the work here
    // let's assume img is the image you've got

    // Prepare a delegate to invoke
    MethodInvoker m = (MethodInvoker)delegate() {
         myImage.Image = img;
    };

    // Invoke it on the UI thread if needed, otherwise
    // do a straight invoke
    if (this.InvokeRequired)
        this.Invoke(m);
    else 
        m.Invoke();
}

答案 3 :(得分:0)

正如其他人所说,你正在向后使用调用。

我的建议在原始处理程序中是这样的:

ThreadPool.QueueUserWorkItem(RequestImage)

然后使用lambda从RequestImage执行Invoke:

RequestImage()
{
  ...
  ...

  Invoke(() => { myControl.BackgroundImage = img; myControl.Width = img; etc, etc });
}

或类似的东西。