Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在C#中的不同线程上运行新窗体?_C#_.net_Winforms_Multithreading_Message Loop - Fatal编程技术网

如何在C#中的不同线程上运行新窗体?

如何在C#中的不同线程上运行新窗体?,c#,.net,winforms,multithreading,message-loop,C#,.net,Winforms,Multithreading,Message Loop,我只是尝试在每次点击按钮时运行一个新线程,这应该会创建一个新表单。我在MainForm中的按钮单击事件中尝试了此操作: private void button1_Click(object sender, EventArgs e) { worker1 = new Thread(new ThreadStart(thread1)); worker2 = new Thread(new ThreadStart(thread2)); worker1.Start(); wor

我只是尝试在每次点击按钮时运行一个新线程,这应该会创建一个新表单。我在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);
    }          
}
private void按钮1\u单击(对象发送者,事件参数e)
{
int max;
尝试
{
max=转换为32(textBox1.Text);
}
抓住
{
MessageBox.Show(“输入数字”、“错误”);
返回;
}
progressBar1.最大值=最大值;
用于(长i=0;i
这条路对吗?因为我试图打开两个独立的窗体,所以一个线程中的操作不应该影响另一个线程


或者BackGroundworker是实现此功能的解决方案?如果是,有人能帮我吗?

您不需要在单独的线程中运行表单。通常,您可以在多个表单上调用
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; };
}

尽管我并没有100%意识到在自己的线程中运行完全独立的表单执行完全独立的操作在任何方面都是危险的,但在单个线程上运行所有UI操作通常被认为是良好的做法

只需让子表单类使用BackgroundWorker,就可以支持这一点。显示表单时,启动BackgroundWorker,以便它处理您需要的任何内容

然后,您只需在GUI线程上创建子窗体的新实例并显示它们。窗体将显示并在另一个线程上开始其操作

这样,UI将在GUI线程上运行,但窗体正在运行的操作将在线程池线程上运行

更新

这里有一个你的背景工作者处理者可能看起来像什么的例子-注意(像往常一样)这只是我的想法,但我认为你可以了解基本原则

将名为worker的BackgroundWorker添加到表单中。将其连接到以下事件处理程序:

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));
    }
}

我希望这会有所帮助。

在不同的线程上运行不同的表单是可能的。我知道有两个警告:

  • 两个表单都不能是另一个表单的MDI客户端。当一个窗体具有不同的线程时,尝试使该窗体成为另一个窗体的MDI客户端将失败。
  • 如果一个对象将向多个窗体发送事件,并且所有窗体都使用同一个线程,则可以在引发事件之前将事件同步到主线程。否则,事件必须异步引发,并且每个表单必须为传入事件执行其自己的同步机制。
    显然,最好不要阻止任何窗口的UI线程,但是为单独的窗口使用单独的线程可能是一个不错的选择。

    试试这个。它使用自己的消息队列在自己的线程上运行新表单。 运行以下代码:

    new Thread(new ThreadStart(delegate
    {
       Application.Run(new Form());
    })).Start();
    

    使用
    Thread.CurrentThread.GetHashCode()
    测试在不同线程上运行的线程。

    我以为Windows应用程序每个进程只有一个GUI事件循环?因此,所有UI工作都需要在主线程中完成?(CMIIW)@user:你特别想解决什么问题?如果我点击主窗体中的按钮两次,它当然会打开两个新窗体,即带有进度条的子窗体和所有窗体。如果给第一个子窗体一个输入,并且它运行了很长时间(比如说我有一个没有结束的进度条),我就不能对打开的第二个子窗体执行任何操作。所以我想独立地打开子窗体。没有“主线程”,任何线程都可以运行自己的消息循环。也可能重复:和@Timwi:谢谢你的回答。但我已经试过了。我的要求其实是不同的。假设我打开了两个子表单,并且子表单1中正在运行一个长进程,我现在可以访问子表单2吗???@Timwi:很抱歉,我第一次没有看到您的更新。这就是我想做的,就像你说的,在一个单独的线程中运行,但不是在表单中运行,但我想知道怎么做?很抱歉,我不熟悉这些,我刚刚开始学习。@user403489,建议不要在子表单1中运行长流程,而是在BackgroundWorker(或线程,但BackgroundWorker使GUI线程交互更易于管理)中运行长流程。否则,您将使子表单1无响应,这导致了丑陋的画作(没有重新粉刷)和其他事情。@Timwi:非常感谢。我来试试这个谢谢Alex Humphrey先生。我确实理解你的回答,一个幕后工作者是最好的做法,但你能在这个例子中帮助我吗。因为,我知道它的作用,但我看到的所有例子都太长了,无法遵循。为了理解简单的东西,我举了一个小例子。我希望这对其他人也有用。谢谢。@user403489:我已经更新了一些示例代码-我希望它能让您了解如何使用BackgroundWorker。谢谢Alex先生。你的帮助对像我这样的人很有用。@Alex:我试过这个,效果很好。非常感谢你。我使用了“Application.Run(s);”我得到的错误不是我最初使用的s.show,而是“Int32.TryParse”似乎不起作用,“TryParse”方法接受“1”参数时没有重载”。我寻找解决办法。我将“max”声明为“int”,并且只使用了“Int32.TryParse”。但我还是犯了那个错误。纽维,我对
    new Thread(new ThreadStart(delegate
    {
       Application.Run(new Form());
    })).Start();