c#线程和显示更新
我有一个带有标签和图片框的Windows窗体。为了从web服务检索图像,我使用了一个线程 用户单击按钮,首先必须显示标签,然后启动新线程检索图像。代码如下: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
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()
并从其主体内返回大小。:)