目前,我知道如何在树视图控件中执行延迟实现节点的加载过程,并在stackoverflow中读取相关问题,但我也在阅读asp.net中的IHierarchyData和IHierarchicalEnumerable接口(I不知道编写asp.net)允许将集合绑定到树视图以自动显示项目。
我想知道我是否可以在winforms和C#中做同样的事情。我认为之前提到的接口在winforms中不可用。
感谢。
答案 0 :(得分:3)
Windows窗体TreeView
不知道如何绑定到IHierarchyData
实例,这并不奇怪,因为IHierarchyData
和相关接口打算供Web控件使用(特别是网站地图)。
但是,构建自己的数据绑定类真的不太难。这似乎是一个有趣的问题所以我把它们放在一起只是为了好玩。我会引导你完成内部工作。
首先,创建一个基本的Component类。 Visual Studio将使用以下代码启动您:
public partial class TreeViewHierarchyBinding : Component
{
public TreeViewHierarchyBinding()
{
InitializeComponent();
}
public TreeViewHierarchyBinding(IContainer container)
{
container.Add(this);
InitializeComponent();
}
}
此组件需要具有的一个显而易见的“状态”是从每个TreeNode
到其IHierarchyData
的映射。现在我们可以通过将它放在TreeNode
的{{1}}属性中来解决这个问题,但是我们的目标是让这个组件尽可能无创,并跟踪它自己的状态。因此,我们将使用字典。将此字段添加到类:
Tag
现在,至少,该组件需要知道如何从其相应绑定的private Dictionary<TreeNode, IHierarchyData> nodeDictionary = new
Dictionary<TreeNode, IHierarchyData>();
填充TreeNode
类的特定父TreeView
,所以让我们接下来编写该代码:
IHierarchyData
这部分应该非常简单。第一种方法使用private void PopulateChildNodes(TreeNodeCollection parentCollection,
IHierarchicalEnumerable children)
{
parentCollection.Clear();
foreach (object child in children)
{
IHierarchyData childData = children.GetHierarchyData(child);
TreeNode childNode = new TreeNode(childData.ToString());
if (childData.HasChildren)
{
childNode.Nodes.Add("Dummy"); // Make expandable
}
nodeDictionary.Add(childNode, childData);
parentCollection.Add(childNode);
}
}
private void UpdateRootNodes(TreeView tv, IHierarchyData hierarchyData)
{
if (tv == null)
{
return;
}
tv.Nodes.Clear();
if (hierarchyData != null)
{
IHierarchicalEnumerable roots = hierarchyData.GetChildren();
PopulateChildNodes(tv.Nodes, roots);
}
}
接口,使用从TreeNodeCollection
实例获取的层次结构填充Nodes
(即TreeNode
的{{1}}属性)。这个方法唯一真正有趣的事情是:
IHierarchyData
实例有子节点时添加虚节点;这使得“+”在树视图中可见,否则我们将无法进一步扩展;以及
将新添加的节点添加到与其匹配的IHierarchyEnumerable
实例的字典中。
第二种方法更简单,它执行初始的“绑定工作”,用我们的顶级IHierarchyData
实例替换树的 root 中的任何内容。
我们的组件需要做的下一件事是挂钩IHierarchyData
的加载事件来执行延迟加载。这是执行此操作的代码:
IHierarchyData
前两个方法应该是不言自明的,第三个方法是实际的延迟加载代码。我们在这里作弊,使用TreeView
属性来描述子节点是否已经加载,因此我们不会进行任何不必要的重新加载。当我实现延迟加载的树时,我总是这样做,因为根据我的经验,我几乎从不使用private void RegisterEvents(TreeView tv)
{
tv.BeforeExpand += TreeViewBeforeExpand;
}
private void UnregisterEvents(TreeView tv)
{
tv.BeforeExpand -= TreeViewBeforeExpand;
}
private void TreeViewBeforeExpand(object sender, TreeViewCancelEventArgs e)
{
if (e.Node.Checked)
{
return;
}
IHierarchyData hierarchyData;
if (nodeDictionary.TryGetValue(e.Node, out hierarchyData))
{
PopulateChildNodes(e.Node.Nodes, hierarchyData.GetChildren());
e.Node.Checked = true;
}
}
属性。但是,如果您确实需要将此属性用于其他内容,则可以使用其他属性(如TreeNode.Checked
),创建另一个字典以保存展开状态,或修改现有字典以保存复合类(包含TreeNode.Checked
以及Tag
属性)。我现在保持简单。
如果您之前在树中实现了延迟加载,其余部分应该已经有意义了,所以让我们跳过。实际上,此时唯一要做的就是实现一些设计师/用户属性,这些属性实际上将连接树和数据:
IHierarchyData
容易腻。我们有一个Expanded
属性,可以接受根private IHierarchyData dataSource;
private TreeView treeView;
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public IHierarchyData DataSource
{
get { return dataSource; }
set
{
if (value != dataSource)
{
dataSource = value;
nodeDictionary.Clear();
UpdateRootNodes(treeView, value);
}
}
}
[Category("Behavior")]
[DefaultValue(null)]
[Description("Specifies the TreeView that the hierarchy should be bound to.")]
public TreeView TreeView
{
get { return treeView; }
set
{
if (value != treeView)
{
if (treeView != null)
{
UnregisterEvents(treeView);
}
treeView = value;
nodeDictionary.Clear();
RegisterEvents(value);
UpdateRootNodes(treeView, dataSource);
}
}
}
和DataSource
属性,您可以从设计器中访问该属性。同样,这里简单的东西,当更新IHierarchyData
属性时,我们只是重置查找并重新填充根。当TreeView
属性更新时,我们需要做更多的工作,注册事件,确保从旧树视图中取消注册事件,并完成我们在数据源更改时所做的所有事情。
真的就是这一切!打开Windows窗体设计器,删除DataSource
,然后删除TreeView
并将其TreeView
属性设置为刚删除的树视图。最后,在你的代码中(即在TreeViewHierarchyBinding
事件中),给它一个数据源:
TreeView
(注意 - 这会使用MSDN page for IHierarchyData上的示例Form_Load
。示例不是非常强大,它不检查private void Form1_Load(object sender, EventArgs e)
{
DirectoryInfo dir = new DirectoryInfo("C:\\");
treeViewHierarchyBinding1.DataSource = new FileSystemHierarchyData(dir);
}
或其他任何内容,但它足够好证明这一点。)
就是这样。运行您的应用并观看它绑定。您现在可以在任何地方重复使用FileSystemHierarchyData
组件 - 只需将其放在表单上,为其分配UnauthorizedAccessException
,然后将TreeViewHierarchyBinding
实例作为数据源。
如果你想要一个复制粘贴版本,我已经放了complete code on PasteBin。
玩得开心!
答案 1 :(得分:1)
接口可用,但需要添加对System.Web.UI的引用。 (它可能还需要您使用完整的.NET Framework可再发行组件而不是客户端配置文件,尽管我不确定。)
更大的问题是:WinForms TreeView控件是否自动了解如何使用这些接口?我相信这个问题的答案是“不”,但你需要测试/验证。
答案 2 :(得分:1)
有一篇有趣的文章here向您展示如何构建扩展方法以实现我认为您正在寻找的东西。 System.Windows.Forms.TreeView中没有本机可用性来绑定到我能找到的集合。
您可以在项目中包含System.Web.UI,以使IHierarchyData和IHierarchicalEnumerable接口可用,但如果没有扩展方法,TreeView将无法附加到它们。
来自网站的示例源代码将允许您将任何IDictionary集合绑定到TreeView。