繁体   English   中英

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

[英]How can I create controls in a non main-thread?

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

反正有摆脱这种情况的方法吗?

我发现问题不在于在新线程中完全创建文档。 我可以做这个。 但是之后我无法显示该文档,因为它不是由主线程创建的。 如果我在主线程中创建它-这就是我所做的-它可以正常工作。 但是随后在生成报告时阻止了该应用程序。

有什么方法可以将对象的所有权转移到另一个线程? 特别是对于UI元素(例如Canvas)? 就像我说的那样,我能够在其他线程中创建报告,但是应用程序拒绝显示它。 无法显示未由主线程创建/拥有的控件。

你不能 任何UI控件都必须由Dispatcher管理

如果绝对需要从另一个线程创建控件,则需要通过主Dispatcher调用它们的创建/添加,同步或异步(取决于您的选择)

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

 Application.Current.Dispatcher.BeginInvoke(new Action(() =>
            {
                // Your control creation here
            }), DispatcherPriority.Background);

我曾经处理过一个类似的问题:Global 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;
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM