Reputation: 1
Everybody.
I've two form as follow by
From1 has a button, when click this Form2 will appear.
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
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
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
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