C# 在后台线程中创建元素,然后添加到主界面

C# 在后台线程中创建元素,然后添加到主界面,c#,.net,wpf,user-interface,multithreading,C#,.net,Wpf,User Interface,Multithreading,我在WPF中有一个线程问题。我想创建一个复杂的用户界面,然后我想把它添加到我的主窗口。在创建这个复杂的用户界面时,我想在主窗口中显示一个进度条。我想这只能用线做。但有一个问题。无法将创建的元素添加到主窗口,因为它是在单独的线程中创建的。 有人知道是否有可能将在后台线程中创建的UIElements传输到主线程。 如果我以一种简单的方式尝试,它会说无法访问该对象,因为它位于一个单独的线程中。我已经使我的进度条线程安全 我希望下面的例子能更好地解释我想要的 StackPanel tcForm = ne

我在WPF中有一个线程问题。我想创建一个复杂的用户界面,然后我想把它添加到我的主窗口。在创建这个复杂的用户界面时,我想在主窗口中显示一个进度条。我想这只能用线做。但有一个问题。无法将创建的元素添加到主窗口,因为它是在单独的线程中创建的。 有人知道是否有可能将在后台线程中创建的UIElements传输到主线程。 如果我以一种简单的方式尝试,它会说无法访问该对象,因为它位于一个单独的线程中。我已经使我的进度条线程安全

我希望下面的例子能更好地解释我想要的

StackPanel tcForm = new StackPanel();
Semaphore loadedSema = new Semaphore(0,1);
Thread thread = new Thread(new ThreadStart(delegate(){
           //Formular should be created in background               
           tcForm.Children.Add(new Formular());
           ProgressBar.AddProgress();
           //...other things
           loadedSema.Release();
}));
thread.start();
loadedSema.WaitOne();
newformular()
运行了很长时间,所以我考虑在后台创建

也不可能将
公式
添加到变量,然后将其添加到主线程

//this is also impossible

//in background-thread
form = new Formular

//in main-thread
tcForm.Children.Add(form);
我希望有办法做到这一点。 如果有什么建议就好了


谢谢,Martin

如果你只想更新一个进度条(或类似的),那么你应该在主线程中提前创建所有UI,然后使用表单将状态更新从后台线程发送到主线程(例如发送一个
int
表示进度介于0和100%之间)

我认为没有办法在线程之间共享windows窗体控件


编辑:好的,我现在看到它被标记为WPF。答案保持不变,但您使用的不是对控件的调用,而是类(每个图形元素都包含对适当调度器的引用)。您也可以按照另一个答案中的建议使用该类。

如果您只想更新进度条(或类似内容),那么您应该在主线程中预先创建所有UI,然后使用表单将状态更新从后台线程发送到主线程(例如发送
int
表示进度介于0和100%之间)

我认为没有办法在线程之间共享windows窗体控件


编辑:好的,我现在看到它被标记为WPF。答案保持不变,但您使用的不是对控件的调用,而是类(每个图形元素都包含对适当调度器的引用)。您也可以按照另一个答案中的建议使用该类。

我对WPF了解不多,但我刚刚了解了BackGroundWorker,它可能会为您完成工作

您只需要处理WorkerCompleted事件,该事件在任务之后引发,应该在主线程中运行。它还可以报告进度以更新进度栏

例如:

    void worker_Start()
    {
        BackgroundWorker worker = new BackgroundWorker();
        worker.DoWork +=
            new DoWorkEventHandler(worker_DoWork);
        worker.RunWorkerCompleted +=
            new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);

        worker.RunWorkerAsync("MyArg");

    }

    void worker_DoWork(object sender, DoWorkEventArgs e)
    {
         e.Result = new Formular();
    }

    void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        this.Controls.Add((Control)e.Result);
    }

我对WPF了解不多,但我刚刚了解了一位可能会为您做这项工作的幕后工作人员

您只需要处理WorkerCompleted事件,该事件在任务之后引发,应该在主线程中运行。它还可以报告进度以更新进度栏

例如:

    void worker_Start()
    {
        BackgroundWorker worker = new BackgroundWorker();
        worker.DoWork +=
            new DoWorkEventHandler(worker_DoWork);
        worker.RunWorkerCompleted +=
            new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);

        worker.RunWorkerAsync("MyArg");

    }

    void worker_DoWork(object sender, DoWorkEventArgs e)
    {
         e.Result = new Formular();
    }

    void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        this.Controls.Add((Control)e.Result);
    }
你应该使用这个方法

编辑
如果Fromular()对象工作时间长,则可以在分派之前创建它

var f = new Formular();
this.Dispatcher.Invoke(delegate{ tcForm.Children.Add(f);
               ProgressBar.AddProgress();};)
你应该使用这个方法

编辑
如果Fromular()对象工作时间长,则可以在分派之前创建它

var f = new Formular();
this.Dispatcher.Invoke(delegate{ tcForm.Children.Add(f);
               ProgressBar.AddProgress();};)

不,那是不可能的。WPF主要是单螺纹的

但是,您应该想知道为什么创建接口需要那么多时间。WPF相当快。“普通”控件创建不应成为瓶颈

也许你可以优化其他对象的创建;尝试分析您的应用程序


然后尝试从下到上构建UI:最后一个操作应该是将控件添加到表单中。

否-这是不可能的。WPF主要是单螺纹的

但是,您应该想知道为什么创建接口需要那么多时间。WPF相当快。“普通”控件创建不应成为瓶颈

也许你可以优化其他对象的创建;尝试分析您的应用程序


然后尝试从下到上构建UI:最后一个操作应该是将控件添加到表单中。

您可以用XAML序列化UI元素,然后将它们发送回主线程。但不确定在主线程中取消序列化是否比在主线程中创建它们更快。

您可以XAML序列化ui元素,然后将它们发送回主线程。不确定在主线程中取消序列化是否比在主线程中创建它们更快。

如果我使用后台工作线程,我会遇到与使用线程相同的问题。这是可以理解的,因为backgroundworker也是一个线程。线程和backgroundworker之间的区别在于backgroundworker是线程池中的现有线程。如果在主线程中创建backgroundworker并附加到WorkerCompleted事件,则此事件处理程序中的代码应在主线程中执行(至少对我有效)。我添加了一个例子。如果我使用后台工作程序,我会遇到与使用线程相同的问题。这是可以理解的,因为backgroundworker也是一个线程。线程和backgroundworker之间的区别在于backgroundworker是线程池中的现有线程。如果在主线程中创建backgroundworker并附加到WorkerCompleted事件,则此事件处理程序中的代码应在主线程中执行(至少对我有效)。我添加了一个示例。这就是当前的工作方式。但如果使用这种方式,问题是进度条必须位于另一个窗口中。此窗口不能是主窗口的子窗口。这是当前的工作方式。但如果使用这种方式,问题是进度条必须位于另一个窗口中。此窗口不能是主窗口的子窗口。