如何在C#中的不同线程上运行新表单?
我只是尝试在每次按钮点击时都运行一个新线程,这应该创建一个新表单。 我在MainForm中的按钮单击事件中尝试了这个:
private void button1_Click(object sender, EventArgs e) { worker1 = new Thread(new ThreadStart(thread1)); worker2 = new Thread(new ThreadStart(thread2)); worker1.Start(); worker2.Start(); } private void thread1() { SubForm s = new SubForm(); s.Show(); } private void thread2() { SubForm s = new SubForm(); s.Show(); }
子窗体按钮单击事件中的代码如下所示:
private void button1_Click(object sender, EventArgs e) { int max; try { max = Convert.ToInt32(textBox1.Text); } catch { MessageBox.Show("Enter numbers", "ERROR"); return; } progressBar1.Maximum = max; for ( long i = 0; i < max; i++) { progressBar1.Value = Convert.ToInt32(i); } }
这是正确的方法吗? 因为我试图打开两个独立的表单,一个线程中的操作不应该影响另一个线程。
或者BackGroundworker是实现这个的解决方案吗? 如果是的话,有人可以帮助我吗?
虽然我不是100%意识到任何说完全独立的表单在自己的线程中完全独立的操作是危险的,但在单个线程上运行所有UI操作通常被认为是一种好习惯。
只需让Subform类使用BackgroundWorker即可支持此function。 显示表单时,启动BackgroundWorker,以便它处理您需要的任何内容。
然后,您可以在GUI线程上创建Subform的新实例并显示它们。 表单将显示并在另一个线程上启动其操作。
这样UI将在GUI线程上运行,但表单运行的操作将在ThreadPool线程上运行。
更新
以下是您的后台工作人员处理程序的示例 – 注意(像往常一样)这只是我的头脑,但我认为您可以了解基本原则。
将BackgroundWorker添加到名为worker的表单中。 将它连接到以下事件处理程序:
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { // Executed on GUI thread. if (e.Error != null) { // Background thread errored - report it in a messagebox. MessageBox.Show(e.Error.ToString()); return; } // Worker succeeded. } void worker_ProgressChanged(object sender, ProgressChangedEventArgs e) { // Executed on GUI thread. progressBar1.Value = e.ProgressPercentage; } void worker_DoWork(object sender, DoWorkEventArgs e) { // Executed on ThreadPool thread. int max = (int)e.Argument; for (long i = 0; i < max; i++) { worker.ReportProgress(Convert.ToInt32(i)); } }
您的点击处理程序看起来像:
void button1_Click(object sender, EventArgs e) { int max; try { // This is what you have in your click handler, // Int32.TryParse is a much better alternative. max = Convert.ToInt32(textBox1.Text); } catch { MessageBox.Show("Enter numbers", "ERROR"); return; } progressBar1.Maximum = max; worker.RunWorkerAsync(max); }
我希望有所帮助。
您不需要在单独的线程中运行表单。 你可以通常在多个表单上调用s.Show()
。 他们不会互相阻挠。
当然,如果你正在做其他事情 ,比如某种计算或需要很长时间的其他任务,那么你应该在一个单独的线程中运行它 ,而不是表单。
这里有一些代码可以让您创建一个显示长进程进度的进度条。 请注意,每次从线程内部访问表单时,都必须使用.Invoke()
,它实际上会在GUI线程准备好时调度该调用。
public void StartLongProcess() { // Create and show the form with the progress bar var progressForm = new Subform(); progressForm.Show(); bool interrupt = false; // Run the calculation in a separate thread var thread = new Thread(() => { // Do some calculation, presumably in some sort of loop... while ( ... ) { // Every time you want to update the progress bar: progressForm.Invoke(new Action( () => { progressForm.ProgressBar.Value = ...; })); // If you're ready to cancel the calculation: if (interrupt) break; } // The calculation is finished — close the progress form progressForm.Invoke(new Action(() => { progressForm.Close(); })); }); thread.Start(); // Allow the user to cancel the calculation with a Cancel button progressForm.CancelButton.Click += (s, e) => { interrupt = true; }; }
可以在不同的线程上运行不同的表单。 我知道有两个警告:
- 这两种forms都不是另一种forms的MDI客户端。 当表单具有不同的线程时,尝试使表单成为另一个的MDI客户端将失败。
- 如果一个对象将事件发送到多个表单并且所有表单都使用相同的线程,则可以在提升之前将事件同步到主线程。 否则,必须异步引发事件,并且每个表单必须为传入事件执行自己的同步机制。
显然,不希望任何窗口的UI线程被阻塞,但是为单独的窗口使用单独的线程可能是一个不错的选择。
试试这个。 它在自己的线程上运行新的Form,它有自己的消息队列,什么不是。 运行此代码:
new Thread(new ThreadStart(delegate { Application.Run(new Form()); })).Start();
使用Thread.CurrentThread.GetHashCode()
来测试它是否在不同的线程上运行。