2013-02-22 150 views
0

我有一個運行無UI的FTP進程。並有一個使用這個ftp控件的winform。在那個窗口中我有一個顯示ftp上傳進度的進度條。進度通過interfase進入窗口,在underliying主持人更新(我使用MVP模式)。使用線程刷新進度條UI

我的問題是當試圖更新進度時,它總是拋出我這個異常。

通過線程非法操作:控制'prgProgresoSubido'是從一個線程訪問,而不是您創建它的線程。

即使我在表單中使用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; 
     } 
    } 
} 

我該怎麼辦才能避免這個問題?

+0

*「這個問題仍然存在,即使我用一個BackgroundWorker」 * - 你可能不正確地使用BackgroudWorker – GolfWolf 2013-02-22 15:33:49

+0

也許....這是我的第一次用它。也許你有一個簡單的?問題是ftp在它自己的Thread中工作,然後我需要克隆另一個trhead來更新進度條? – 2013-02-22 15:34:47

+0

'BackgroudWorker'應該很簡單:使用ReportProgress方法顯示當前的進度並處理ProgressChanged事件中的UI部分(將在正確的線程中調用)。請參閱http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.progresschanged.aspx – GolfWolf 2013-02-22 15:36:34

回答

1

正如Alan剛剛指出的那樣,您必須在UI線程中使用UI控件執行所有操作。

只需修改你的財產是這樣的:

public int ProgresoSubida 
{ 
    set 
    { 
     MethodInvoker invoker = delegate 
           { 
            prgProgresoSubido.Value = value; 
           } 
     if (this.InvokeRequired) 
     { 
      Invoke(invoker); 
     } 
     else 
     { 
      invoker(); 
     } 

    } 
} 
+0

Tks。那適合像手套一樣。 – 2013-02-22 15:59:56

2

通常,對用戶界面和控件的所有更新都必須從主線程(事件分派器)完成。如果您嘗試從其他線程修改控件的屬性,您將會遇到異常。

必須調用Control.Invoke對事件調度調用,更新你的UI

Control.Invoke

這裏的方法中,放置一個按鈕和一個窗體上的標籤,那就試試這個

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可能會爲您提供一些機制(如評論員所說)爲您簡化了這一操作,但是我之前從未使用過,因此我會將其留給您進行調查。

+0

對不起,如果不明白,但是我第一次使用線程...也許你有樣品嗎? – 2013-02-22 15:33:52

+0

@JuanPabloGomez在MSDN上的鏈接中有一個例子,但我會盡量把東西扔在一起 – Alan 2013-02-22 15:34:48

+0

很多,它將會非常讚賞。 – 2013-02-22 15:40:20