我知道我不能生成不同的线程并将它放在 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/