Yoonmy
Yoonmy

Reputation: 1

Close Form when Thread has finished

Everybody.

I've two form as follow by

  1. From1 has a button, when click this Form2 will appear.

  2. From2 has a Progressbar, It's counting and update Progressbar from Maximun value until It has finished, Form2 will close.

This below code of Form2

public delegate void ProgressbarHandler(int value);
public partial class Form2 : Form
{

    public event WaitCallback CloseThreadEvent;

    private Thread t;

    public void OnCloseEvent(ThreadState state)
    {
        if (CloseThreadEvent != null)
            CloseThreadEvent(state);
    }

    public Form2()
    {
        InitializeComponent();

        progressBar1.Minimum = 0;
        progressBar1.Maximum = 20000;
    }
    private void Form2_Load(object sender, EventArgs e)
    {
        InitThread();
    }

    private void InitThread()
    {
        t = new Thread(new ThreadStart(RunThread));
        t.Start();

        CloseThreadEvent += new WaitCallback(CloseForm);

        Thread tt = new Thread(ThreadObserver);
        tt.IsBackground = true;
        tt.Start();
    }
    private void RunThread()
    {
        for (int i = 0; i < progressBar1.Maximum; i++)
        {
            progressBar1.Invoke(new ProgressbarHandler(UpdateProgressbar), i);
        }
    }
    private void UpdateProgressbar(int value)
    {
        progressBar1.Value = value + 1;
    }

    private void ThreadObserver()
    {
        while (t.IsAlive)
        {
            OnCloseEvent(t.ThreadState);
        }
    }
    private void CloseForm(Object state)
    {
        if ((ThreadState)state == ThreadState.Stopped)
            this.Close();
    }
}

From my code, It has a "Cross-thread operation not valid" error on

this.Close();

Please give suggestion, How to coding follow by my purpose.

Thank you.

Upvotes: 0

Views: 8658

Answers (3)

Eben Roux
Eben Roux

Reputation: 13246

You can only access controls from the thread they were created on. A form is also a control.

Have a look at Control.Invoke.

I use a class similar to this to handle these scenarios:

public static class ControlExtensions
{
    public static void Invoke(this Control control, Action action)
    {
        if (control.InvokeRequired)
        {
            control.Invoke(new MethodInvoker(action), null);
        }
        else
        {
            action.Invoke();
        }
    }
}

Then you would be able to call this.Invoke(() => Close()); to close your form.

Upvotes: 3

Yoonmy
Yoonmy

Reputation: 1

Thank you, Everybody

It works!!

    public partial class Form2 : Form
{  
    private Thread tstart, trun;

    public Form2()
    {
        InitializeComponent();

        progressBar1.Minimum = 0;
        progressBar1.Maximum = 100;
    }
    private void Form2_Load(object sender, EventArgs e)
    {
        tstart = new Thread(InitThread);
        tstart.Start();
    }

    private void InitThread()
    {
        trun = new Thread(new ThreadStart(RunThread));
        trun.Start();
        trun.Join();

        CloseForm(trun.ThreadState);
    }
    private void RunThread()
    {
        for (int i = 0; i < progressBar1.Maximum; i++)
        {
            Thread.Sleep(10);
            progressBar1.Invoke(new MethodInvoker(delegate { progressBar1.Increment(1); }));                            
        }
    }
    private void CloseForm(Object state)
    {
        if ((ThreadState)state != ThreadState.Stopped)               
            return;            
        else
        {
            if (this.InvokeRequired)
                this.Invoke(new MethodInvoker(delegate { this.Close(); }), null);
        }
    }

    private void Form2_FormClosing(object sender, FormClosingEventArgs e)
    {
        if (tstart.IsAlive)
            tstart.Abort();
        if (trun.IsAlive)
            trun.Abort();
    }

}

Upvotes: 0

Craig White
Craig White

Reputation: 13992

Pretty simple fix.

this.Invoke(new MethodInvoker(delegate { this.Close(); }));

I don't know why you didn't think of it? Isn't it obvious? :P

Upvotes: 2

Related Questions