c#线程和显示更新

c#线程和显示更新,c#,winforms,multithreading,C#,Winforms,Multithreading,我有一个带有标签和图片框的Windows窗体。为了从web服务检索图像,我使用了一个线程 用户单击按钮,首先必须显示标签,然后启动新线程检索图像。代码如下: private void menuItem1_Click(object sender, EventArgs e) { etiquetaCargando.Visible = true; this.Invoke(new System.Threading.ThreadStart(RequestImage)); } 问题是:etiquet

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

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

private void menuItem1_Click(object sender, EventArgs e)

{

etiquetaCargando.Visible = true;

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

}
问题是:etiquetaCargando标签没有出现

我在Compact框架上编程

发生了什么事


谢谢

这个问题还不清楚,但是使用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,该方法将实际执行在表单上显示图像的任务。

问题不清楚,但使用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,该方法将实际执行在表单上显示图像的任务。

您不应该调用此方法:

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线程上执行的委托,在本例中,传递您下载的图像。

您不应该调用此方法:

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线程上执行的委托,在本例中,传递下载的图像。

您可以执行以下操作:

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

您可以执行以下操作:

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

正如其他人所说,您正在反向使用调用

我的建议类似于您最初的处理程序:

ThreadPool.QueueUserWorkItem(RequestImage)
然后使用lambda从RequestImage执行调用:

RequestImage()
{
  ...
  ...

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

或者类似的东西。

正如其他人所说,您正在反向使用调用

我的建议类似于您最初的处理程序:

ThreadPool.QueueUserWorkItem(RequestImage)
然后使用lambda从RequestImage执行调用:

RequestImage()
{
  ...
  ...

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


或者类似的问题。

问题是什么还不清楚。你是在试图解决问题,还是在问如何启动线程?etiquetaCargando标签没有出现。不清楚问题是什么。是否有您正在尝试修复的问题,或者您正在询问如何启动线程?etiquetaCargando标签没有出现。请不要忘记启动新的t.;)如果我这样做,标签会显示出来,但我不能对从web服务检索到的图像进行签名。@VansFannel:您应该确保您分配给的任何内容都可用于RequestImage方法。然后,在该方法中,您将把它传递给一个委托,然后再传递给Invoke方法如果我这样做,标签会显示出来,但我不能对从web服务检索到的图像进行签名。@VansFannel:您应该确保您分配给的任何内容都可用于RequestImage方法。然后,在该方法中,您会将其传递给一个委托,并将其传递给Invoke方法。在方法RequestImage中,我必须访问此属性:this.Height this.Width我如何检索这两个属性的值?@VansFannel:您应该能够直接访问它们,否则您可以将大小传递给参数化的ThreadStart,并让RequestImage将大小作为参数在方法RequestImage中我必须访问此属性:this.Height this.Width如何检索这两个属性的值?@VansFannel:您应该能够直接访问它们,否则可以将大小传递到参数化的ThreadStart,并让RequestImage将大小作为参数可能是这样。没有必要使用IsBackground。在RequestImage中,我需要访问两个属性:this.Height和this.Width。我如何做到这一点?您可以通过声明自己的方法委托(
delegate Size getSizeDelegate(Control c);
代码中的其他地方),用
getSizeDelegate将
MethodInvoker
替换为
getSizeDelegate
,将
Control c
添加到
delegate()
并从其主体内返回大小。:)也许这是不必要的。在RequestImage中,我需要访问两个属性:this.Height和this.Width。如何实现这一点?您可以使用
System.Drawing.Size
IIRC访问它们,方法是声明您自己的方法委托(
delegate Size getSizeDelegate(Control c);
在代码中的其他地方),将
MethodInvoker
替换为
getSizeDelegate
,将
Control c
添加到
delegate()
并从其主体内返回大小。:)