代码之家  ›  专栏  ›  技术社区  ›  martin

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

  •  1
  • martin  · 技术社区  · 15 年前

    我对wpf中的线程有问题。我想创建一个复杂的用户界面,然后我想把它添加到我的主窗口。当这个复杂的用户界面创建时,我想在主窗口中显示一个进度条。我想这个只能用线做。但有个问题。无法将创建的元素添加到主窗口,因为它是在单独的线程中创建的。 有人知道是否有可能将在后台线程中创建的uielement转移到主线程。 如果我试着用一种简单的方法,它会说对象不能被访问,因为它在一个单独的线程中。我的进度条已经安全了。

    我希望下面的例子能更好地解释我想做的事情。

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

    new Formular() 运行了很长时间,所以我考虑在后台创建。

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

    //this is also impossible
    
    //in background-thread
    form = new Formular
    
    //in main-thread
    tcForm.Children.Add(form);
    

    我希望有办法。 如果有什么建议就好了,

    谢谢,马丁

    5 回复  |  直到 14 年前
        1
  •  3
  •   Arsen Mkrtchyan    15 年前

    你应该用 Dispatcher.Invoke 方法

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

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

    var f = new Formular();
    this.Dispatcher.Invoke(delegate{ tcForm.Children.Add(f);
                   ProgressBar.AddProgress();};)
    
        2
  •  1
  •   Jürgen Steinblock    15 年前

    我对wpf不太了解,但我刚刚了解了一个可以为你做这项工作的后台工作人员。

    http://dotnetperls.com/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);
        }
    
        3
  •  1
  •   Isak Savo    15 年前

    如果您只想更新一个进度条(或类似的),那么您应该在主线程的前面创建所有ui,然后使用表单的 Invoke method (例如发送一个 int 说进度在0%到100%之间

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

    编辑: 好的,我现在看到这个被标记为wpf。答案仍然是相同的,但是不是在控件上调用,而是使用 Dispatcher 类(每个图形元素都包含对适当分派器的引用)。您也可以使用 BackgroundWorker 按照另一个答案的建议上课。

        4
  •  0
  •   Matthias    15 年前

    不-那是不可能的。wpf主要是单线程的。

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

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

    尝试自下而上构建用户界面:最后一个操作应该是将控件添加到表单中。

        5
  •  0
  •   keft    14 年前

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