使用线程刷新进度条UI
本文关键字:UI 刷新 线程 | 更新日期: 2023-09-27 18:00:29
我有一个在没有UI的情况下运行的FTP进程。并具有使用此ftp控件的winform。在那个窗口中,我有一个进度条,显示ftp上传进度。进度通过基础演示者上更新的interbase到达窗口(我使用MVP模式)。
我的问题是,当试图更新进度时,它总是会给我带来这个异常。
通过线程非法操作:控件"prgProgresoSubido"是从创建它的线程以外的线程访问的。
即使我在Form中使用BackGroundWorker,这个问题仍然存在。
// This is a delegated on presenter when a File finish to upload
void client_FileUploadCompletedHandler(object sender, FileUploadCompletedEventArgs e)
{
string log = string.Format("{0} Upload from {1} to {2} is completed. Length: {3}. ",
DateTime.Now, e.LocalFile.FullName, e.ServerPath, e.LocalFile.Length);
archivosSubidos += 1;
_Publicacion.ProgresoSubida = (int)((archivosSubidos / archivosXSubir) * 100);
//this.lstLog.Items.Add(log);
//this.lstLog.SelectedIndex = this.lstLog.Items.Count - 1;
}
// This is My interfase
public interface IPublicacion
{
...
int ProgresoSubida { set; }
}
/// And Here is the implementartion of the interfase on the form
public partial class PublicarForm : Form ,IPublicacion
{
//Credenciales para conectarse al servicio FTP
public FTPClientManager client = null;
public XmlDocument conf = new XmlDocument();
public string workingDir = null;
public webTalk wt = new webTalk();
private readonly PublicacionesWebBL _Publicador;
public PublicarForm()
{
InitializeComponent();
String[] laPath = { System.AppDomain.CurrentDomain.BaseDirectory};
String lcPath = System.IO.Path.Combine(laPath);
_Publicador = new PublicacionesWebBL(this, lcPath);
}
public int ProgresoSubida
{
set
{
// This is my prograss bar, here it throw the exception.
prgProgresoSubido.Value = value;
}
}
}
我该如何避免这个问题?
通常,用户界面和控件的所有更新都必须从主线程(事件调度器)完成。如果您试图从不同的线程修改控件的属性,您将得到一个异常。
您必须调用Control。Invoke在事件调度程序上调用更新UI 的方法
控制。调用
在这里,在表格上放置一个按钮和标签,然后尝试这个
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ThreadStart(TestThread));
t.Start();
}
private void TestThread()
{
for (int i = 0; i < 10; i++)
{
UpdateCounter(i);
Thread.Sleep(1000);
}
}
private void UpdateCounter(int i)
{
if (label1.InvokeRequired)
{
label1.Invoke(new ThreadStart(delegate { UpdateCounter(i); }));
}
else
{
label1.Text = i.ToString();
}
}
}
要意识到,如果您从一个线程中激发一个事件,那么该事件将在同一个线程上。因此,如果该线程不是事件调度器,则需要调用。
此外,BackgroundWorker可能会给你一些机制(正如评论员所说)来简化这一点,但我以前从未使用过,所以我将让你来调查。
正如Alan刚刚指出的,您必须在UI线程中使用UI控件执行所有操作。
只需这样修改您的属性:
public int ProgresoSubida
{
set
{
MethodInvoker invoker = delegate
{
prgProgresoSubido.Value = value;
}
if (this.InvokeRequired)
{
Invoke(invoker);
}
else
{
invoker();
}
}
}