Winforms 中的 IHierarchyData 和 IHierarchicalEnumerable
目前,我知道如何在树视图控件中延迟实现节点的加载过程,并阅读了 stackoverflow 中的相关问题,但我也在阅读有关 asp.net 中的 IHierarchyData 和 IHierarchicalEnumerable 接口(我没有知道编码 asp.net),允许将集合绑定到树视图,以便自动显示项目。
它想知道我是否可以在 winforms 和 C# 中做同样的事情。我认为前面提到的接口在winforms中不可用。
谢谢。
Currently,I know how to do a lazy implementation of the loading procedure of the nodes in a treeview control, and read the related questions in stackoverflow, but I'm also reading about IHierarchyData and IHierarchicalEnumerable interfaces in asp.net (I didn't know to code asp.net) that allow to bind a collection to a treeview in order to display the items automatically.
It would like to know if I can do the same in winforms and C#. I think that the interfaces previous mentioned are not available in winforms.
Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
Windows 窗体
TreeView
不知道如何绑定到IHierarchyData
实例,考虑到IHierarchyData
和相关接口的预期目的,这并不奇怪供 Web 控件(尤其是站点地图)使用。然而,构建您自己的数据绑定类实际上并不太难。这似乎是一个有趣的问题,所以我只是为了好玩而把一个问题放在一起。我将引导您了解内部运作方式。
首先,创建一个基本的 Component 类。 Visual Studio 将从这样的代码开始:
该组件需要具有的一个明显的“状态”是从每个
TreeNode
到其IHierarchyData
的映射。现在我们可以通过将其放入TreeNode
的Tag
属性来解决这个问题,但我们的目标是使该组件尽可能非侵入性并跟踪它自己的状态。因此,我们将使用字典。将此字段添加到类中:现在,该组件至少需要知道如何从其相应绑定的
填充
,所以接下来让我们编写该代码:TreeView
类的特定父TreeNode
IHierarchyData这部分应该非常简单。第一个方法只是使用从
IHierarchyData
获取的层次结构填充TreeNodeCollection
(即TreeNode
的Nodes
属性) > 实例,使用IHierarchyEnumerable
接口。此方法唯一真正有趣的事情是:当 IHierarchyData 实例有子节点时添加虚拟节点;这使得“+”在树视图中可见,否则我们将无法进一步展开;
使用与之匹配的
IHierarchyData
实例将新添加的节点添加到字典中。第二种方法更简单,它执行初始“绑定工作”,用我们的顶级
IHierarchyData
实例替换树的root 中的任何内容。我们的组件需要做的下一件事是挂钩 TreeView 中的加载事件以执行延迟加载。下面是执行此操作的代码:
前两个方法应该是不言自明的,第三个方法是实际的延迟加载代码。我们在这里做了一点欺骗,使用 TreeNode.Checked 属性来描述子节点是否已经加载,这样我们就不会进行任何不必要的重新加载。当我实现延迟加载树时,我总是这样做,因为根据我的经验,我几乎从不使用
TreeNode.Checked
属性。但是,如果您确实需要将此属性用于其他用途,则可以使用不同的属性(例如Tag
),创建另一个字典来保存扩展状态,或者修改现有字典来保存复合类(包含IHierarchyData
以及Expanded
属性)。我现在保持简单。如果您之前已经在树中实现了延迟加载,那么其余的内容应该已经对您有意义,所以让我们跳过。实际上,此时唯一要做的就是实现一些设计者/用户属性,这些属性将实际连接树和数据:
简单。我们有一个接受根
IHierarchyData
的DataSource
属性,以及一个您可以从设计器访问的TreeView
属性。同样,这里的事情很简单,当 DataSource 属性更新时,我们只需重置查找并重新填充根。当TreeView
属性更新时,我们必须做更多的工作,注册事件,确保从旧树视图中注销事件,并执行数据源更改时所做的所有相同操作。这真的就是全部了!打开 Windows 窗体设计器,放置一个
TreeView
,然后放置一个TreeViewHierarchyBinding
,并将其TreeView
属性设置为刚刚放置的树视图。最后,在代码中的某个位置(即在Form_Load
事件中),为其提供一个数据源:(注意 - 这使用 IHierarchyData 的 MSDN 页面。该示例不是很强大,它不会检查 UnauthorizedAccessException 或任何其他内容,但它足以证明这一点)。
就是这样。运行您的应用程序并观察它的绑定。现在,您可以在任何地方重用
TreeViewHierarchyBinding
组件 - 只需将其放在表单上,为其分配一个TreeView
,并为其提供一个IHierarchyData
实例作为数据源。如果您想要复制粘贴版本,我已将完整代码放在PasteBin上。
玩得开心!
The Windows Forms
TreeView
does not know how to bind to anIHierarchyData
instance, which isn't surprising given that theIHierarchyData
and related interfaces are intended for consumption by web controls (especially site maps).However, it's really not too hard to build your own data binding class. This seemed like an interesting problem so I threw one together just for fun. I'll walk you through the inner workings.
First, create a basic Component class. Visual Studio will start you off with code like this:
One obvious piece of "state" this component needs to have is a mapping from each
TreeNode
to itsIHierarchyData
. Now we can hack around this by throwing it in theTreeNode
'sTag
property, but let's aim to make this component as non-invasive as possible and keep track of its own state. Hence, we'll use a dictionary. Add this field to the class:Now, at a minimum, this component needs to know how to populate a specific parent
TreeNode
of aTreeView
class from its correspondingly boundIHierarchyData
, so let's write that code next:This part should be pretty straightforward. The first method just populates a
TreeNodeCollection
(i.e. theNodes
property of aTreeNode
) with the hierarchy obtained from anIHierarchyData
instance, using theIHierarchyEnumerable
interface. The only really interesting things this method does are:Adding a dummy node when the
IHierarchyData
instance has children; this makes the "+" visible in the tree view, otherwise we wouldn't be able to expand any deeper; andAdding the newly-added node to the dictionary with the
IHierarchyData
instance it matches with.The second method is even simpler, it does the initial "binding work", replacing whatever is in the root of the tree with our top-level
IHierarchyData
instance.The next thing our component needs to be able to do is hook the loading events from the
TreeView
to perform lazy-loading. Here's the code to do that:First two methods should be self-explanatory, and the third method is the actual lazy-loading code. We're cheating a little here, using the
TreeNode.Checked
property to delineate whether or not the child nodes have already been loaded so we don't do any unnecessary reloads. I always do this when I implement lazy-loaded trees because, in my experience, I almost never use theTreeNode.Checked
property. However, if you do need to use this property for something else, you can either use a different property (likeTag
), create another dictionary to hold the expanded states, or modify the existing dictionary to hold a composite class (containing theIHierarchyData
as well as anExpanded
property). I'm keeping it simple for now.The rest should already make sense to you if you've implemented lazy-loading in a tree before, so let's skip ahead. Really the only thing left to do at this point is implement some designer/user properties that will actually wire up the tree and data:
Easy peasy. We've got a
DataSource
property that accepts the rootIHierarchyData
, and aTreeView
property which you'll be able to access from the designer. Again, simple stuff here, when theDataSource
property is updated, we just reset the lookup and repopulate the root. When theTreeView
property is updated we have to do a little more work, registering the events, making sure to unregister events from the old tree view, and doing all the same stuff we do when the data source changes.That's really all there is to it! Open up the Windows Forms designer, drop a
TreeView
, then drop aTreeViewHierarchyBinding
and set itsTreeView
property to the tree view you just dropped. Finally, in your code somewhere (i.e. in theForm_Load
event), give it a data source:(Note - this uses the example
FileSystemHierarchyData
that's on the MSDN page for IHierarchyData. The example isn't very robust, it doesn't check forUnauthorizedAccessException
or anything, but it's good enough to demonstrate this).And that's it. Run your app and watch it bind. You can now reuse the
TreeViewHierarchyBinding
component anywhere - just drop it on a form, assign it aTreeView
, and give it anIHierarchyData
instance as a data source.I've put the complete code on PasteBin if you want a copy-and-paste version.
Have fun!
这些接口可用,但需要您添加对 System.Web.UI 的引用。 (它可能还要求您使用完整的 .NET Framework 可再发行组件而不是 Client Profile,尽管我对此并不确定。)
更大的问题是:WinForms TreeView 控件是否自动理解如何使用这些接口?我相信这个问题的答案是“否”,但您需要测试/验证这一点。
The interfaces are available, but will require you to add a reference to System.Web.UI. (It might also require you to use the full .NET Framework redistributable rather than the Client Profile, although I'm not certain about that.)
The larger question is: Does the WinForms TreeView control automatically understand how to work with these interfaces? I believe the answer to that question is "No", but you would need to test/verify that.
有一篇有趣的文章 这里向您展示了如何构建扩展方法来实现我认为您正在寻找的目标。 System.Windows.Forms.TreeView 中没有本机可用性来绑定到我能找到的集合。
您可以在项目中包含 System.Web.UI 以使 IHierarchyData 和 IHierarchicalEnumerable 接口可用,但如果没有扩展方法,TreeView 将无法附加到它们。
该网站的示例源代码将允许您将任何 IDictionary 集合绑定到 TreeView。
There's an interesting article here that shows you how to build extension methods to achieve what I think you're looking for. There is no native availability within the System.Windows.Forms.TreeView to bind to a collection from what I can find.
You CAN include System.Web.UI in your project to make the IHierarchyData and IHierarchicalEnumerable interfaces available, but the TreeView will not be able to attach to them without the extension methods.
The sample source code from the web site will let you bind any IDictionary collection to the TreeView.