在WPF中创建大量用户控件

本文关键字:用户 控件 创建 WPF | 更新日期: 2023-09-27 18:29:02

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

我目前的场景是,我在运行时大量创建UI控件,比如200(FrameworkContentElement)控件,并将其添加到DockWindow中。我是否可以在创建UI时不冻结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;
    }

EDIT:这些控件也是FrameworkContentElement,在这种情况下虚拟化控件没有帮助。这与FlowDocument控件在运行时创建控件有关。例如,运行、表、段落等。因此,ListBox、TreeViews等不适用于此场景。

在WPF中创建大量用户控件

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

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

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

"活动"一词指的是列表视图所采取的方法,其中实际项目被虚拟化——它们只在需要时创建,如果不可见则被处理。因此,如果UI允许,可以考虑使用虚拟化容器,如ListView,而不是DockPanel;

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