c# - 在 WPF 中创建大量用户控件

标签 c# wpf .net-4.0

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

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

我想到的一种方法是创建 UI 控件并将它们序列化到 MemoryStream 中并将它们加载到 UI 线程,这里的一个问题是我必须将 DataContext 重新附加到控件但是没关系,在那一刻我可以将它委托(delegate)给另一个线程。问题仍然是这样做可行吗?

我尝试混合 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等不适用于此场景。

最佳答案

200 个控件应该不会造成太大的问题,因为在像样的机器上渲染 WPF 可能需要几千个基元

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

...话虽这么说 - 如果您的 UI 太重,您可能设计有误。问题不应该是 “在我的 UI 变慢变成拖拽之前,我可以放置多少 UI 元素?” 但 “可以完成这项工作的事件 UI 元素的最小数量是多少?”。

“事件”一词指的是 ListView 采用的方法,其中实际项目被虚拟化——它们仅在需要时创建,如果不可见则丢弃。因此,如果您的 UI 允许,请考虑使用虚拟化容器(例如 ListView)而不是 DockPanel;

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

关于c# - 在 WPF 中创建大量用户控件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18450186/

相关文章:

java - 如何生成 CUSIP 校验位

c# - 向简单 Web 服务请求添加 header

c# - 从文本框复制后,重音字符无法正确显示

c# - 如何将 List<Anonymous Type> 转换为 List<string>

.net-4.0 - CLR 4 的托管堆栈资源管理器

c# - 有效地合并列表列表

c# - 将目标框架从 .NetStandard 2.0 更改为 .net 4.7.2 后无法进行 nuget 恢复

C# 正则表达式匹配一行中的精确字符串但忽略大小写

c# - WPF:特定输入文本框(用于电话号码等)

wpf - WPF-当Command.CanExecute为false时更改Button控件模板背景