Jorne De Blaere
Jorne De Blaere

Reputation: 39

invalidOperationException while using delegate in thread

I divided my programme in 3 layers; GUI, BL, IO and tried to grap files from my server to my pc. I made it multi threaded and zorks fine, but when i tried to add a delegate to it for sending messages from my IO to my GUI, it troubels me. It said something like:

It is not allowed to perform an operation through various threads: it was from another thread had access to the control label download progress than the thread on which the element is created.

What i have is this:

GUI

private void buttonDownload_Click(object sender, EventArgs e)
{
    download = new BL_DataTransfer(Wat.FILM, titel, this.downloadDel);
    t = new Thread(new ThreadStart(download.DownLoadFiles));    
    t.Start();
}
private void UpdateDownloadLabel(string File)
{
        labelDownloadProgress.Text = "Downloading: " + File;
}

BL

    public void DownLoadFiles()
    {
        //bestanden zoeken op server
        string map = BASEDIR + this.wat.ToString() + @"\" + this.titel + @"\";
        string[] files = IO_DataTransfer.GrapFiles(map);

        //pad omvormen
        string[] downloadFiles = this.VeranderNaarDownLoadPad(files,this.titel);
        IO_DataTransfer.DownloadFiles(@".\" + this.titel + @"\", files, downloadFiles, this.obserdelegate);
    }

IO

    public static void DownloadFiles(string map, string[] bestanden, string[] uploadPlaats, ObserverDelegate observerDelegete)
    {
        try
        {
            Directory.CreateDirectory(map);

            for (int i = 0; i < bestanden.Count(); i++)
            {
                observerDelegete(bestanden[i]);
                File.Copy(bestanden[i], uploadPlaats[i]);
            }
        }
        catch (UnauthorizedAccessException uoe) { }
        catch (FileNotFoundException fnfe) { }
        catch (Exception e) { }        
    }

Delgate

 public delegate void ObserverDelegate(string fileName);

Upvotes: 0

Views: 659

Answers (2)

ChrisF
ChrisF

Reputation: 137148

Assuming that it's the update of the label that's failing you need to marshal the event onto the UI thread. To do this change your update code to be:

private void UpdateDownloadLabel(string File)
{
    if (labelDownloadProgress.InvokeRequired)
    {
        labelDownloadProgress.Invoke(new Action(() =>
            {
                labelDownloadProgress.Text = "Downloading: " + File;
            });
    }
    else
    {
        labelDownloadProgress.Text = "Downloading: " + File;
    }
}

I've ended up creating an extension method for this that I can call - thus reducing the amount of repeated code in my applications:

public static void InvokeIfRequired(this Control control, Action action)
{
    if (control.InvokeRequired)
    {
        control.Invoke(action);
    }
    else
    {
        action();
    }
}

Which is then called like this:

private void UpdateDownloadLabel(string File)
{
    this.labelDownloadProgress.InvokeIfRequired(() =>
       labelDownloadProgress.Text = "Downloading: " + File);
}

Upvotes: 1

Tigran
Tigran

Reputation: 62246

if UpdateDownloadLabel function is in some control code-file, use pattern like this:

private void UpdateDownloadLabel(string File)
{
     this.Invoke(new Action(()=> {
             labelDownloadProgress.Text = "Downloading: " + File;
      })));
}

You need to invoke assignment on UI thread in order to be able to change something on label.

Upvotes: 0

Related Questions