如何使用DevExpress WPF组件实现异步加载TreeList节点?建议收藏
DevExpress WPF拥有120+个控件和库,将帮助您交付满足甚至超出企业需求的高性能业务应用程序。通过DevExpress WPF能创建有着强大互动功能的XAML基础应用程序,这些应用程序专注于当代客户的需求和构建未来新一代支持触摸的解决方案。
在本文中,我们将详细介绍如何在DevExpress WPF TreeList控件和WPF Data Grid的TreeListView中异步加载树节点。
DevExpress技术交流群7:674691612 欢迎一起进群讨论
当从一个服务中获取数据或加载一个有很多子记录的节点时,应用程序可能会在节点扩展期间暂时“冻结”,为了解决这个问题现在可以在后台线程中加载子节点。启用此选项后,应用程序UI将在加载/展开操作期间保持响应。
当加载信息时,WPF TreeList控件将在屏幕上显示等待指示器。一旦完成,节点将被展开,等待指示器将被隐藏。
要在下一个WPF项目中引入此功能,请创建一个实现iasyncchildnodeselector接口的类,并重写SelectChildrenAsync方法。当用户展开节点并允许开发人员在后台线程中加载子节点时,选择器将调用此方法,该方法返回一个Task对象(其中包含加载的子记录的集合):
public class AsyncChildrenSelector : IAsyncChildNodesSelector { public Task<bool> HasChildNode(object item, CancellationToken token) { throw new NotImplementedException(); } public IEnumerable SelectChildren(object item) { throw new NotImplementedException(); } public Task<IEnumerable> SelectChildrenAsync(object item, CancellationToken token) { return Task.Run(async () => { await Task.Delay(1000); return SelectChildNodes(item); }); } public IEnumerable SelectChildNodes(object item) { if (item is ProjectStage) return (item as ProjectStage).StageTasks; else if (item is ProjectObject) return (item as ProjectObject).ProjectStages; return null; } }
接下来,重写HasChildNode方法来检查加载的节点是否有子节点。当加载所有子节点时,选择器调用此方法。该方法返回一个Task对象,该对象包含一个布尔值(指示加载的节点是否包含子节点)。基于这个值,WPF TreeList控件显示节点的展开按钮:
public class AsyncChildrenSelector : IAsyncChildNodesSelector { public Task<bool> HasChildNode(object item, CancellationToken token) { return Task.Run(async () => { await Task.Delay(250); return !(item is StageTask); }); } public IEnumerable SelectChildren(object item) { throw new NotImplementedException(); } public Task<IEnumerable> SelectChildrenAsync(object item, CancellationToken token) { return Task.Run(async () => { await Task.Delay(1000); return SelectChildNodes(item); }); } public IEnumerable SelectChildNodes(object item) { if (item is ProjectStage) return (item as ProjectStage).StageTasks; else if (item is ProjectObject) return (item as ProjectObject).ProjectStages; return null; } }
开发人员可以允许最终用户取消任何加载操作,为了响应用户的取消请求而取消加载操作,调用SelectChildrenAsync或HasChildNode方法中的CancellationToken.ThrowIfCancellationRequested()方法。如果实现了,WPF TreeList控件将在用户取消加载操作时显示一个重试按钮。这个“refresh”按钮允许用户重新启动操作:
public class CustomChildrenSelector : IAsyncChildNodesSelector { public Task<bool> HasChildNode(object item, CancellationToken token) { return Task.Run(async () => { for (int i = 0; i < 10; i++) { token.ThrowIfCancellationRequested(); await Task.Delay(25); } return !(item is StageTask); }); } public IEnumerable SelectChildren(object item) { throw new NotImplementedException(); } public Task<IEnumerable> SelectChildrenAsync(object item, CancellationToken token) { return Task.Run(async () => { for (int i = 0; i < 10; i++) { token.ThrowIfCancellationRequested(); await Task.Delay(100); } return SelectChildNodes(item); }); } public IEnumerable SelectChildNodes(object item) { if (item is ProjectStage) return (item as ProjectStage).Tasks; else if (item is ProjectObject) return (item as ProjectObject).Stages; return null; } }
将TreeListView.TreeDerivationMode属性设置为ChildNodesSelector,然后将创建的类实例分配给TreeListView.ChildNodesSelector属性:
<dxg:TreeListControl ...> <dxg:TreeListControl.Resources> <local:AsyncChildrenSelector x:Key="childrenSelector"/> </dxg:TreeListControl.Resources> <dxg:TreeListControl.View> <dxg:TreeListView TreeDerivationMode="ChildNodesSelector" ChildNodesSelector="{StaticResource childrenSelector}"/> </dxg:TreeListControl.View> </dxg:TreeListControl>