我可以更改 WPF 中控件的线程关联性(调度程序)吗?

发布于 2024-09-18 05:21:27 字数 138 浏览 7 评论 0原文

我想创建一个需要一段时间才能创建(透视)的控件,然后将其添加到可视化树中。为此,我需要在将控件添加到 VisualTree 之前更改控件的调度程序(及其层次结构)。

这可能吗?遍历控件树并通过反射设置 _dispatcher 字段是否有任何影响?

I want to create a control which takes a while to create (Pivot) and then add it to the visual tree. To do this i would need to change the dispatcher of the control (and its heirachy) before adding it to the VisualTree.

Is this possible? Are there any implications of walking the controls trees and setting the _dispatcher field via reflection?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

醉酒的小男人 2024-09-25 05:21:27

AFAIK 这只适用于 Freezable 派生类。我看到的最好的解决方案是在 UI 线程上创建控件并在创建过程中显示进度条。为了实现这一点,您必须分部分创建控件,并让进度条偶尔更新一次。这不仅对于进度条是必要的,而且还可以确保您的应用程序不会阻塞。

伪代码(在额外线程中执行):

this.Dispatcher.BeginInvoke(UpdateProgress(0));
this.Dispatcher.BeginInvoke(bigControlBuilder.Build(0,25));
this.Dispatcher.BeginInvoke(UpdateProgress(25));
this.Dispatcher.BeginInvoke(bigControlBuilder.Build(25,50));
this.Dispatcher.BeginInvoke(UpdateProgress(50));
this.Dispatcher.BeginInvoke(bigControlBuilder.Build(50,75));
this.Dispatcher.BeginInvoke(UpdateProgress(75));
this.Dispatcher.BeginInvoke(bigControlBuilder.Build(75,100));
this.Dispatcher.BeginInvoke(UpdateProgress(100));
this.Dispatcher.BeginInvoke(this.Children.Add(bigControlBuilder.GetControl()));

更新:

为了使复杂的控制更具响应性,您还可以尝试 UI 虚拟化/数据虚拟化:

仅加载并显示用户当前可见的数据项的那些可视项。不要加载和显示滚动到屏幕外的视觉项目,这些项目太小而无法看到或以任何其他方式对用户不可见。在用户交互时卸载变得不可见的项目,加载变得可见的项目。

AFAIK this only works with Freezable derived classes. The best solution I see is to create the control on the UI Thread and show a progress bar during creation. To make this possible you will have to create the control in portions an let the progress bar update itself once in a while. This not only necessary for the progressbar but also will make sure that you application does not block.

Pseudocode (execure in extra thread):

this.Dispatcher.BeginInvoke(UpdateProgress(0));
this.Dispatcher.BeginInvoke(bigControlBuilder.Build(0,25));
this.Dispatcher.BeginInvoke(UpdateProgress(25));
this.Dispatcher.BeginInvoke(bigControlBuilder.Build(25,50));
this.Dispatcher.BeginInvoke(UpdateProgress(50));
this.Dispatcher.BeginInvoke(bigControlBuilder.Build(50,75));
this.Dispatcher.BeginInvoke(UpdateProgress(75));
this.Dispatcher.BeginInvoke(bigControlBuilder.Build(75,100));
this.Dispatcher.BeginInvoke(UpdateProgress(100));
this.Dispatcher.BeginInvoke(this.Children.Add(bigControlBuilder.GetControl()));

Update:

To make complex control more responsive you could also try UI-Virtualization/Data-Virtualisation:

Only load and show those visual items of the data items that are currently visible to ther user. Do not load and show visual items that are scrolled offscreen are to small to see or are in any other way invisible to the user. Upon userinteraction unload items that become invisble, load items that become visible.

很糊涂小朋友 2024-09-25 05:21:27

为了回答您的问题,我认为使用反射设置 _dispatcher 是可能,但我根本不推荐它。 WPF 中有一个根深蒂固的线程亲和性和 STA 概念,所以我不会搞乱它。

bitbonk 的方法是一个很好的方法。
我们在项目中使用的另一种方法是创建第二个 UI 线程,并在第一个 UI 线程构建 UI 时由第二个 UI 线程呈现进度指示器。只要进度条停留在第二个 UI 线程拥有的可视化树中,就应该没问题。

To answer your question, I suppose it is possible to set _dispatcher using reflection but I would not recommend it at all. There is a deeply ingrained notion in WPF of thread affinity and STA so I wouldn't mess with that.

bitbonk's approach is a good one.
Another approach we have used in a project of ours was to create a second UI thread and have a progress indicator be rendered by the second UI thread while the first UI thread is building the UI. As long as the progress bar stays in the visual tree owned by the second UI thread, you should be good.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文