C# 如何在非主线程中创建控件?

C# 如何在非主线程中创建控件?,c#,wpf,multithreading,user-interface,C#,Wpf,Multithreading,User Interface,在我们的应用程序中,我们能够打印报告。对于这些报告,我们使用类,如FlowDocument、Canvas和一些其他控件,如Labels。由于控件只能在主线程中创建,因此应用程序会显示一个通知窗口,用户必须等待。一份报告最多可以有100页,因此这可能需要几分钟的时间。用户无法对应用程序执行任何其他操作 有没有办法摆脱这种局面 正如我发现的,问题并不完全是在新线程中创建文档。我能做到。但是我无法在以后显示文档,因为它不是由主线程创建的。如果我在主线程中创建它-这就是我所做的-它工作得很好。但是,在生

在我们的应用程序中,我们能够打印报告。对于这些报告,我们使用类,如FlowDocument、Canvas和一些其他控件,如Labels。由于控件只能在主线程中创建,因此应用程序会显示一个通知窗口,用户必须等待。一份报告最多可以有100页,因此这可能需要几分钟的时间。用户无法对应用程序执行任何其他操作

有没有办法摆脱这种局面

正如我发现的,问题并不完全是在新线程中创建文档。我能做到。但是我无法在以后显示文档,因为它不是由主线程创建的。如果我在主线程中创建它-这就是我所做的-它工作得很好。但是,在生成报告时,应用程序被阻止


有没有办法将对象的所有权转移到另一个线程?尤其是像画布这样的UI元素?正如我之前所说,我可以在一个附加线程中创建报告,但应用程序拒绝显示它。无法显示非主线程创建/拥有的控件。

您不能。任何UI控件都必须由
调度程序管理

如果您确实需要从另一个线程创建控件,则需要根据您的选择通过主Dispatcher、sync或async调用控件的创建/添加

异步调用的快速示例(将
BeginInvoke
更改为
Invoke
进行同步,并相应地使用
DispatcherPriority


我曾经处理过一个类似的问题:全局
DockManager
,动态处理停靠内容,我必须从Dispatcher创建控件,才能将它们实际添加到我的
DockManager
。确保在这些调用中避免任何争用情况,您应该会很好

我建议创建一个带有调度程序的新线程。在这个单独的线程中,您可以创建元素树并在独立于主窗口UI线程的单独窗口中显示它。然后用户可以选择打印或不打印

要创建一个新线程,并在其上初始化WPF调度程序,可以使用以下代码:

public class DispatcherBuilder : IBuilder<Dispatcher>
{
    public Dispatcher Build()
    {
        Dispatcher dispatcher = null;
        var manualResetEvent = new ManualResetEvent(false);
        var thread = new Thread(() =>
            {
                dispatcher = Dispatcher.CurrentDispatcher;
                var synchronizationContext = new DispatcherSynchronizationContext(dispatcher);
                SynchronizationContext.SetSynchronizationContext(synchronizationContext);

                manualResetEvent.Set();
                Dispatcher.Run();
            });
        thread.Start();
        manualResetEvent.WaitOne();
        manualResetEvent.Dispose();
        return dispatcher;
    }
}
公共类DispatcherBuilder:IBuilder
{
公共调度程序生成()
{
Dispatcher=null;
var manualResetEvent=新的manualResetEvent(错误);
变量线程=新线程(()=>
{
dispatcher=dispatcher.CurrentDispatcher;
var synchronizationContext=新的DispatcherSynchronizationContext(dispatcher);
SynchronizationContext.SetSynchronizationContext(SynchronizationContext);
manualResetEvent.Set();
Dispatcher.Run();
});
thread.Start();
manualResetEvent.WaitOne();
manualResetEvent.Dispose();
返回调度员;
}
}

处理这种大小的文档需要比现成的基本组件更好的解决方案。这需要一个定制的解决方案。没有看到您的代码,很难提出任何建议。。。
public class DispatcherBuilder : IBuilder<Dispatcher>
{
    public Dispatcher Build()
    {
        Dispatcher dispatcher = null;
        var manualResetEvent = new ManualResetEvent(false);
        var thread = new Thread(() =>
            {
                dispatcher = Dispatcher.CurrentDispatcher;
                var synchronizationContext = new DispatcherSynchronizationContext(dispatcher);
                SynchronizationContext.SetSynchronizationContext(synchronizationContext);

                manualResetEvent.Set();
                Dispatcher.Run();
            });
        thread.Start();
        manualResetEvent.WaitOne();
        manualResetEvent.Dispose();
        return dispatcher;
    }
}