Juan Pablo Gomez
Juan Pablo Gomez

Reputation: 5534

Refresh Progressbar UI using Thread

I have a FTP proccess that run without UI. and have a winform that use this ftp control. in that window I have a progressbar that show the ftp upload progress. The progress arrives to the window via interfase that is updated on the underliying presenter (I'm using MVP pattern).

My problem is when try to update the progress, it allways throw me this exception.

Through threads illegal operation: control 'prgProgresoSubido' is accessed from a thread other than that in which you created it.

That problem persists even if I use a BackGroundWorker in the Form.

    // 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;
        }
    }
}

How can I do to avoid this problem ?

Upvotes: 0

Views: 139

Answers (2)

Ronnix
Ronnix

Reputation: 310

As Alan has just pointed out, you must do all operations with UI controls in UI thread.

Just modify your property like this:

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

    }
}

Upvotes: 1

Alan
Alan

Reputation: 7951

In general, all updates to the User Interface and Controls has to be done from the main thread (event dispatcher). If you attempt to modify the properties of a control from a different thread you will get an exception.

You must call Control.Invoke to invoke on the event dispatcher the method that updates your UI

Control.Invoke

Here, place a button and a label on a form, then try this

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

Realize, that if you are firing an event from a thread, that the event will be on the same Thread. Therefore, if that thread is not the event dispatcher, you'll need to invoke.

Also, there may be mechanisms that BackgroundWorker gives you (As the commentator said) that simplify this for you, but I've never used it before so I'll leave that up to you to investigate.

Upvotes: 2

Related Questions