C# 从对象填充树视图
我的WinForm应用程序中的C# 从对象填充树视图,c#,.net,winforms,linq-to-sql,treeview,C#,.net,Winforms,Linq To Sql,Treeview,我的WinForm应用程序中的treeview有问题。我创建了一个保存数据的TreeViewItem类。只有5个字段:CaseNoteID、ContactDate、ParentNoteID、InsertUser、ContactDetails。 public class TreeItem { public Guid CaseNoteID; public Guid? ParentNoteID; public string ContactDate; public str
treeview
有问题。我创建了一个保存数据的TreeViewItem类。只有5个字段:CaseNoteID、ContactDate、ParentNoteID、InsertUser、ContactDetails。
public class TreeItem
{
public Guid CaseNoteID;
public Guid? ParentNoteID;
public string ContactDate;
public string InsertUser;
public string ContactDetails;
public TreeItem(Guid caseNoteID, Guid? parentNoteID, string contactDate, string contactDetails, string insertUser)
{
CaseNoteID = caseNoteID;
ParentNoteID = parentNoteID;
ContactDate = contactDate;
ContactDetails = contactDetails;
InsertUser = insertUser;
}
}
计划是通过在父项下显示一个由ParentNoteID字段确定的注释来显示注释之间的关系。真是太简单了。不幸的是,到目前为止,我所有的尝试都在两个位置都放置了一个“child”注释,其中一个带有ParentNoteID。第一级及其相应父级下的
当我逐步完成我的代码时,我的数据会准确地返回
List<TreeItem> items = BLLMatrix.GetTreeViewData(HUD.PersonId);
PopulateTree(tvwCaseNotes,items);
我只是好像没办法控制住它。我是否需要拆分我的数据调用,首先返回所有带有ParentNoteID=null
的条目,然后获取其余的条目并以某种方式将它们合并起来
@霍根:我为问题中的剧烈变化道歉。从你的回答中可以明显看出,我一开始并没有从一个好的角度来看待这个问题。其次,原始方法仍然不起作用。递归的基本思想是将堆栈用作每次调用变量的临时存储。但是,在递归调用中引用的是全局变量。当您更改它时(通过filter函数),它将使递归中所有先前的调用无效。您需要删除递归或在堆栈上推送控制变量(行)的新副本(而不是像现在这样的引用) 根据评论进行编辑 我讨厌在没有测试的情况下把代码放在那里,但我相信这样做应该可以解决我描述的问题 以下是问题所在:
// using the Find method uses a Predicate generic delegate.
if (nodeList.Find(FindNode) == null)
{
var tmpCNoteID = dr["CaseNoteID"].ToString();
var filter = "ParentNote='" + tmpCNoteID + "'";
DataRow[] childRows = cNoteDT.Select(filter);
if (childRows.Length > 0)
{
// Recursively call this function for all childRows
TreeNode[] childNodes = RecurseRows(childRows);
// Add all childnodes to this node
node.Nodes.AddRange(childNodes);
}
// Mark this noteID as dirty (already added)
nodeList.Add(node);
}
类似这样的东西应该可以解决我看到的问题(注意:这不是优雅或好的代码,它只是解决了我上面描述的问题,我永远不会把我的名字写在这段代码中)。而且,如果不能测试代码,我甚至不能确定这就是问题所在
// using the Find method uses a Predicate generic delegate.
if (nodeList.Find(FindNode) == null)
{
var tmpCNoteID = dr["CaseNoteID"].ToString();
var filter = "ParentNote='" + tmpCNoteID + "'";
DataTable DTCopy = cNoteDT.Copy()
DataRow[] childRows = DTCopy.Select(filter);
if (childRows.Length > 0)
{
// Recursively call this function for all childRows
TreeNode[] childNodes = RecurseRows(childRows);
// Add all childnodes to this node
node.Nodes.AddRange(childNodes);
}
// Mark this noteID as dirty (already added)
nodeList.Add(node);
}
递归的基本思想是使用堆栈作为每次调用变量的临时存储。但是,在递归调用中引用的是全局变量。当您更改它时(通过filter函数),它将使递归中所有先前的调用无效。您需要删除递归或在堆栈上推送控制变量(行)的新副本(而不是像现在这样的引用) 根据评论进行编辑 我讨厌在没有测试的情况下把代码放在那里,但我相信这样做应该可以解决我描述的问题 以下是问题所在:
// using the Find method uses a Predicate generic delegate.
if (nodeList.Find(FindNode) == null)
{
var tmpCNoteID = dr["CaseNoteID"].ToString();
var filter = "ParentNote='" + tmpCNoteID + "'";
DataRow[] childRows = cNoteDT.Select(filter);
if (childRows.Length > 0)
{
// Recursively call this function for all childRows
TreeNode[] childNodes = RecurseRows(childRows);
// Add all childnodes to this node
node.Nodes.AddRange(childNodes);
}
// Mark this noteID as dirty (already added)
nodeList.Add(node);
}
类似这样的东西应该可以解决我看到的问题(注意:这不是优雅或好的代码,它只是解决了我上面描述的问题,我永远不会把我的名字写在这段代码中)。而且,如果不能测试代码,我甚至不能确定这就是问题所在
// using the Find method uses a Predicate generic delegate.
if (nodeList.Find(FindNode) == null)
{
var tmpCNoteID = dr["CaseNoteID"].ToString();
var filter = "ParentNote='" + tmpCNoteID + "'";
DataTable DTCopy = cNoteDT.Copy()
DataRow[] childRows = DTCopy.Select(filter);
if (childRows.Length > 0)
{
// Recursively call this function for all childRows
TreeNode[] childNodes = RecurseRows(childRows);
// Add all childnodes to this node
node.Nodes.AddRange(childNodes);
}
// Mark this noteID as dirty (already added)
nodeList.Add(node);
}
也许我完全误解了你,但是你有一个扁平的层次结构,每个元素都知道它的父元素。现在必须创建每个元素,然后建立层次结构。下面是此类实现的第一个快速示例(缺少循环检查、错误处理等):
公共部分类表单1:表单
{
公共表格1()
{
初始化组件();
PopulateTreeView(treeView,SampleData());
}
私有IEnumerable SampleData()
{
返回新项目{CaseID=“1”};
返回新项目{CaseID=“2”};
返回新项目{CaseID=“3”};
返回新项目{CaseID=“4”,ParentID=“5”};
产生返回新项目{CaseID=“5”,ParentID=“3”};
返回新项目{CaseID=“6”};
产生返回新项目{CaseID=“7”,ParentID=“1”};
产生返回新项目{CaseID=“8”,ParentID=“1”};
}
私有void PopulateTreeView(树视图树,IEnumerable项)
{
Dictionary allNodes=new Dictionary();
foreach(项目中的var项目)
{
变量节点=CreateTreeNode(项目);
添加(item.CaseID,Tuple.New(item,node));
}
foreach(所有节点中的var kvp)
{
if(kvp.Value.First.ParentID!=null)
{
allNodes[kvp.Value.First.ParentID].Second.Nodes.Add(kvp.Value.Second);
}
其他的
{
tree.Nodes.Add(kvp.Value.Second);
}
}
}
私有树节点CreateTreeNode(项目)
{
var node=new TreeNode();
node.Text=item.CaseID;
返回节点;
}
}
公共类项目
{
公共字符串CaseID{get;set;}
公共字符串ParentID{get;set;}
}
公共类元组
{
公共元组(T优先)
{
第一=第一;
}
公共T第一个{get;set;}
}
公共类Tuple:Tuple
{
公共元组(T第一,T2第二)
:基础(第一)
{
秒=秒;
}
公共T2秒{get;set;}
}
公共静态类元组
{
//允许Tuple.New(1,“2”)而不是New Tuple(1,“2”)
公共静态元组新(T1)
{
返回新元组(t1);
}
新的公共静态元组(T1、T2)
{
返回新的元组(t1,t2);
}
}
什么是元组?
只需回答评论中的问题:
- 看一看
- 看看这个
string CaseID
),它引用两个对象(TreeNode
和Item
)。另一种方法是制作两个字典,分别为Dictionary
和Dictionary
,但由于存在1:1的关系,我采用了元组方法
也许可以将其重命名为ItemTreeNodeContainer
,它会让您更清楚它在conc中的含义
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
PopulateTreeView(treeView1, SampleData());
}
private IEnumerable<Item> SampleData()
{
yield return new Item { CaseID = "1" };
yield return new Item { CaseID = "2" };
yield return new Item { CaseID = "3" };
yield return new Item { CaseID = "4", ParentID = "5" };
yield return new Item { CaseID = "5", ParentID = "3" };
yield return new Item { CaseID = "6" };
yield return new Item { CaseID = "7", ParentID = "1" };
yield return new Item { CaseID = "8", ParentID = "1" };
}
private void PopulateTreeView(TreeView tree, IEnumerable<Item> items)
{
Dictionary<string, Tuple<Item, TreeNode>> allNodes = new Dictionary<string, Tuple<Item, TreeNode>>();
foreach (var item in items)
{
var node = CreateTreeNode(item);
allNodes.Add(item.CaseID, Tuple.Create(item, node));
}
foreach (var kvp in allNodes)
{
if (kvp.Value.Item1.ParentID != null)
{
allNodes[kvp.Value.Item1.ParentID].Item2.Nodes.Add(kvp.Value.Item2);
}
else
{
tree.Nodes.Add(kvp.Value.Item2);
}
}
}
private TreeNode CreateTreeNode(Item item)
{
var node = new TreeNode();
node.Text = item.CaseID;
return node;
}
}
public class Item
{
public string CaseID { get; set; }
public string ParentID { get; set; }
}