如何在WPF中重写TreeViewItem以允许异步加载子项?

3

我正在使用MVVM作为我的WPF架构,并且我已经实现了WPF TreeView的延迟加载(只有在展开时才会递归加载子项)。

然而,我还需要在展开时实现异步加载。有没有一种方法可以做到这一点?我需要将其保持在控件级别,而不是在代码后台/应用程序级别。

谢谢


我想在控件中实现这个的原因是因为递归属性在数据模型中,我不想实现UI线程管理。另外,我想要为treeViewItem添加额外的样式,以便在加载子项时显示一个小GIF。希望这有所帮助。 - undefined
4个回答

2
为什么需要在控件本身实现此功能?
假设这不是绝对要求,我会在返回指定节点的子项属性中处理此问题。如果尚未填充子项,请使用后台线程加载子项,并在找到它们时通知UI线程,然后将子对象添加到子项集合中。假设您正在使用ObservableCollection(或至少实现了INotifyCollectionChanged的集合),当子项被添加时,它们将异步出现在UI中。

0

以下是如何实现的:

  1. 创建一个类型为IEnumerable的附加属性
  2. 在属性的PropertyChanged处理程序中,将sender强制转换为TreeViewItem并检查IsExpanded属性。
  3. 如果IsExpanded为true,则以ApplicationPriority.ApplicationIdle优先级进行Dispatcher.BeginInvoke到您的填充例程
  4. 如果IsExpanded为false,则设置一个事件来检测它何时变为true,并在回调中对Dispatcher.BeginInvoke进行填充例程
  5. 在您的填充例程中,将目标控件的ItemsSource设置为附加属性值
  6. 使用样式在TreeViewItem上设置您的附加属性,而不是通过HierarchicalDataTemplate设置它(在那里省略ItemsSource)

这可以防止TreeViewItem在展开之前设置其ItemsSource。 创建此机制需要一些工作,但一旦创建,您可以通过仅从HierarchicalDataTemplate中删除ItemsSource并在ItemContainerStyle中设置它来使任何TreeView延迟加载。


0

如果您使用懒加载和分层数据模板,您只会得到您所选中的项。请记住,TreeView需要加载比其显示的一级更低的级别,以确定它是否应该显示展开/折叠切换按钮。


-3
对于每个需要延迟加载的UI元素,我使用了一个“视图GUID”。
示例说明:
1. 开始时,Control.Tag =“0000-0000 ....” 2. 用户进行交互,
- 生成一个随机GUID,即guid1 - Control.Tag = guid1 - 创建一个线程,将(要执行的操作、控件、guid1)作为参数
3. 在此之间,用户进行另一个交互,
- 生成一个新的随机GUID(这次是guid2) - Control.Tag = guid2 - 再创建一个线程,将(要执行的操作、控件、guid2)作为参数
4. 第一个线程完成:
- 它调用一个代码到UI线程中,该代码获取结果和执行之前接收到的guid - 调用的代码检查Control.Tag!= guid1,不做任何更改
5. 第二个线程完成:
- 它将一个代码调用到UI线程中,该代码获取结果和执行之前接收到的guid - 被调用的代码看到Control.Tag == guid2,进行更改

这是什么鬼?这是WPF。为什么要使用Tag属性和字符串来实现这个功能?为什么需要在每次用户交互时运行自定义代码?这听起来像是在谈论更原始的技术,比如WinForms或Flash/AIR,在这些技术中这是必要的。而且不清楚这会如何与TreeView交互。在我看来,这根本没有回答问题。 - Ray Burns
我同意使用标签:使用自己的依赖属性是更好的选择。 - bohdan_trotsenko
当预计GetChildren()需要花费时间时,将调用放在单独的线程中是有意义的。然后就存在同步问题,而GUID可以解决这个问题。 - bohdan_trotsenko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接