akinuri
akinuri

Reputation: 12027

"Invoke or BeginInvoke cannot be called on a control until" on a Label

I've read several questions/answers related to this problem but couldn't find a solution applicable to problem.

I have a form (MainForm) and a button (Upload) on it. When I click on the button (after selecting a file from a ComboBox to be uploaded to the server), it opens another form (UploadBackupForm) and uploads a file to the server. The upload process is controlled in UploadBackupForm and the form looks like this:

Screenshot from the app

This works as long as upload is done once, I mean, the UploadBackupForm is called one time. The second time I click on the Upload button, UploadBackupForm opens and (after uploading some data) it throws an error saying:

System.InvalidOperationException: 'Invoke or BeginInvoke cannot be called on a control until the window handle has been created.'

at this specific line(s):

DurationLabel.Invoke((MethodInvoker)delegate
{
    DurationLabel.Text = Count2Duration(count);
});

This has puzzled me because it works when it's done once, and doesn't work at the second time. I have basic knowdledge in C#, so I don't know what's causing this and how to solve it.

MainForm:

private void Upload2ServerButton_OnClick(object sender, EventArgs e)
{
    Form UBF = new UploadBackupForm();
    UBF.ShowDialog();
}

UploadBackupForm:

public partial class UploadBackupForm : Form
{
    public UploadBackupForm()
    {
        InitializeComponent();
    }

    public static System.Timers.Timer timer = new System.Timers.Timer();
    public static int count = 0;

    private void UploadBackup_Load(object sender, EventArgs e)
    {
        timer.Interval = 1000;

        timer.Elapsed += new ElapsedEventHandler(delegate {
            count++;
            // didn't do any good (this.IsHandleCreated or DurationLabel.IsHandleCreated)
            // if (!this.IsHandleCreated)
            // {
                // this.CreateControl();
            // }
            DurationLabel.Invoke((MethodInvoker)delegate
            {
                DurationLabel.Text = Count2Duration(count);
            });
        });

        // upload the archive to the server
        new Thread((ThreadStart)delegate
        {
            FTP.Item[] items = FTP.ListDirectoryDetails(DataIO.FTP.Server, DataIO.FTP.Username, DataIO.FTP.Password, DataIO.FTP.UploadDir);

            // here, I upload the file to the server and update the progress bar and the uploaded / total labels

Upvotes: 1

Views: 431

Answers (1)

BartoszKP
BartoszKP

Reputation: 35911

Because the timer variable is static it remains even after the form is closed. It contains a reference to a delegate which holds a reference to the form so the previous instances are kept alive through the lifetime of your application. Also, the single timer posts callbacks to all previous instances along with the current one.

As correctly noted in the comments by Evk, make the timer and count non-static so they are dedicated to each instance of the form.

Upvotes: 3

Related Questions