4

我知道我不能生成不同的线程并将其放入 UI 线程中以将其添加到 Visual Tree 中,因为它会抛出一个异常,它无法访问该对象,因为不同的线程拥有它。

我目前的情况是我正在大量创建 UI 控件运行时,比如200 (FrameworkContentElement) 控件并将其添加到 DockWindow。我是否可以在创建此 UI 时不冻结 UI 并尝试将它们加载到 UI 线程?我什至无法显示进度对话框,因为它会在显示对话框同时在另一个线程上工作时使用 UI 线程,如果我需要处理的是数据并将其放入 UI 中,那没关系,但这次我需要创建这些用户界面控件。

我认为的一种方法是创建 UI 控件并将它们序列化到 MemoryStream 并将它们加载到 UI 线程,这里的一个问题是我必须将 DataContext 重新附加到控件,但这很好,那一刻我可以将其委托给另一个线程。问题仍然是这样做可行吗?

我尝试混合 Task 和 Thread 对象以使 ApartmentState 成为 STA,但仍然没有运气。

public static Task<T> StartSTATask<T>(Func<T> func)
    {
        var tcs = new TaskCompletionSource<T>();
        Thread thread = new Thread(() =>
        {
            try
            {
                tcs.SetResult(func());
            }
            catch (Exception e)
            {
                tcs.SetException(e);
            }
        });
        thread.SetApartmentState(ApartmentState.STA);
        thread.Start();
        return tcs.Task;
    }

编辑:这些控件又是 FrameworkContentElement,在这种情况下虚拟化控件无济于事。这是在运行时创建控件的 FlowDocument 控件。说,运行,表格,段落等。因此,ListBox、TreeViews等不适用于此场景。

4

1 回答 1

2

200 个控件不应该造成那么大的问题,在一台像样的机器上渲染 WPF 可能需要几千个基元

您可以在加载数据和解析数据时显示进度条。然后,如果需要,您可以通过对数据进行非 UI 线程处理循环并调用 UI 线程来实例化控件来限制创建 UI 元素。您甚至可以通过小睡眠来分离实例以让屏幕呈现,但仅将其用于非常繁重的 UI...

...话虽如此 - 如果您的 UI 如此沉重,您可能设计错了。问题不应该是“在我的 UI 变慢到拖拽之前,我可以放置多少 UI 元素?” 但是“可以完成这项工作的活动UI 元素的最少数量是多少?”。

“活动”一词是指列表视图所采用的方法,其中实际项目被虚拟化 - 它们仅根据需要创建并在不可见时处置。因此,如果您的 UI 允许,请考虑使用虚拟化容器(例如 ListView)而不是 DockPanel;

如果您可以提供特定 UI 元素的示例,我可以进一步详细说明。

于 2013-08-26T18:15:53.697 回答