jika saya memanggil form.show()
pada objek WinForms dari thread lain, form akan melempar pengecualian. Apakah ada cara lain untuk menambahkan form baru yang dapat dilihat ke thread aplikasi utama? Jika tidak, bagaimana saya bisa membuka form tanpa menghentikan thread yang sedang saya jalankan?
Berikut adalah contoh kode saya. Saya mencoba untuk memulai sebuah thread dan kemudian mengeksekusi beberapa pekerjaan di dalam thread tersebut. Saat pekerjaan berlangsung, saya akan menampilkan formulir.
public void Main()
{
new Thread(new ThreadStart(showForm)).Start();
// Rest of main thread goes here...
}
public void showForm()
{
// Do some work here.
myForm form = new myForm();
form.Text = "my text";
form.Show();
// Do some more work here
}
Coba gunakan panggilan invoke:
public static Form globalForm;
void Main()
{
globalForm = new Form();
globalForm.Show();
globalForm.Hide();
// Spawn threads here
}
void ThreadProc()
{
myForm form = new myForm();
globalForm.Invoke((MethodInvoker)delegate() {
form.Text = "my text";
form.Show();
});
}
Panggilan "invoke" memberitahu formulir "Tolong jalankan kode ini di thread Anda daripada thread saya." Anda kemudian dapat membuat perubahan pada UI WinForms dari dalam delegasi.
Dokumentasi lebih lanjut tentang Invoke ada di sini: http://msdn.microsoft.com/en-us/library/zyzhdc6b.aspx
EDIT: Anda perlu menggunakan objek WinForms yang sudah ada untuk memanggil invoke. Saya telah menunjukkan di sini bagaimana Anda dapat membuat objek global; jika tidak, jika Anda memiliki objek windows lainnya, itu juga akan berfungsi.
Anda harus memanggil Application.Run()
setelah anda memanggil form.Show()
. Sebagai contoh:
public void showForm()
{
// Do some work here.
myForm form = new myForm();
form.Text = "my text";
form.Show();
Application.Run();
// Do some more work here
}
Adapun rincian di balik alasannya, posting msdn ini dapat membantu.
Cara terbaik menurut pengalaman saya:
var ac = (ReportPre)Application.OpenForms["ReportPre"];
Thread shower = new Thread(new ThreadStart(() =>
{
if (ac == null)
{
this.Invoke((MethodInvoker)delegate () {
ac = new ReportPre();
ac.Show();
});
}
else
{
this.Invoke((MethodInvoker)delegate
{
pictureBox1.Visible = true;
});
if (ac.InvokeRequired)
{
ac.Invoke(new MethodInvoker(delegate {
ac.Hide();
ac.Show();
}));
}
}
}));
shower.Start();