MVC 中的树视图绑定






4.67/5 (2投票s)
树视图绑定的算法。
引言
很多时候,我们需要以treeview
(树形视图)的形式显示数据,例如显示文件夹结构。这个解决方案的最佳特点是不必担心treeview
的层级,因为我在很多关于treeview
的文章中发现,它们都对层级有限制,或者层级是静态的。我们可以通过多种方式绑定treeview
,例如通过 XML 或通过treeview
对象,但使用 XML 的问题在于我们需要额外的逻辑来创建 XML。因此,我提供了一个非常简单的解决方案来绑定treeview
,为此我们需要将数据存储在列表中。我将这篇文章详细阐述,以便它可以应用于任何类型的语言,这就是为什么我更专注于算法而不是源代码的原因。
算法
这个算法分为两个部分,即
- 为每个节点分配唯一值,以及
- 基于唯一值生成
treeview
为每个节点分配唯一值
算法
- 从列表中获取下一个项目并按“/”分割
- 从分割后的项目中获取下一个节点
- 如果节点包含扩展名,则直接返回到步骤 a。
- 如果节点索引为零,则在节点后附加一些文本,例如“
<N1>
”。 - 如果节点索引大于零,则以以下方式在节点后附加文本
节点=节点的前一个字符(索引-1)+节点+节点后一个字符(索引+1)
- 返回到步骤 b。
源代码
Data <string>=
{
"A/F1.txt"
"A/B/F2.txt"
"A/B/F3.txt"
"A/B/C/F4.txt"
"A/B/C/F5.txt"
"A/D/C/F6.txt"
"A/D/C/F7.txt"
}
List<string> Data = new List<string>();
List<string> ResultData = new List<string>();
for (int i = 0; i < Data.Count; ++i)
{
string Result = "";
Data[i] = Data[i].Replace('\\', '/');
for (int j = 0; j < Data[i].Split('/').Length; ++j)
{
string BindText = Data[i].Split('/')[j];
if (j == 0)
{
BindText = BindText + "<12>";
Result = BindText;
}
else if (BindText.Contains("."))
{
Result = Result + "/" + BindText;
}
else
{
BindText = BindText + "<" + Data[i].Split('/')[j - 1].Substring(0, 1) +
"XZE" + BindText.Substring(0, 1) + ">";
Result = Result + "/" + BindText;
}
}
ResultData.Add(Result);
}
示例
输入值
List= {
"A/F1.txt"
"A/B/F2.txt"
"A/B/F3.txt"
"A/B/C/F4.txt"
"A/B/C/F5.txt"
"A/D/C/F6.txt"
"A/D/C/F7.txt"
}
输出值
List= {
"A<N1>/F1.txt"
"A<N1>/B<ABC>/F2.txt"
"A<N1>/B<ABC>/F3.txt"
"A<N1>/B<ABC>/C<BC>/F4.txt"
"A<N1>/B<ABC>/C<BC>/F5.txt"
"A<N1>/D<ADC>/C<DC>/F6.txt"
"A<N1>/D<ADC>/C<DC>/F7.txt"
}
2. 基于先前算法分配的唯一 ID 生成 Treeview 对象
算法
- 声明
CurrentNode
,RootNode
- 从列表中获取下一个项目并按“/”分割
- 从分割后的项目中获取下一个节点
- 如果节点是第一个项目且索引为零,则
CurrentNode=CreateNode();
RootNode=CurrentNode;
- 否则,如果节点索引为零,则
CurrentNode= RootNode;
- 否则,如果节点是文件名,则
MyNode= CreateNode();
- 将
MyNode
添加到CurrentNode
- Else
Text=GetNodeName(node);
ID=GetNodeID(node);
- 在
CurrentNode
中查找ID
- 如果不匹配,则
MyNode=CreateNode()
- 将
MyNode
添加到CurrentNode
- 否则(表示匹配),则
CurrentNode=GetNodeBasedOnID(ID);
- 如果不匹配,则
- 如果节点是列表的最后一个项目,则退出
- 如果节点是最后一个项目,则转到步骤 b,否则转到步骤 c。
源代码
Data<string>=
{
"A<N1>/F1.txt",
"A<N1>/B<ABC>/F2.txt",
"A<N1>/B<ABC>/F3.txt",
"A<N1>/B<ABC>/C<BC>/F4.txt",
"A<N1>/B<ABC>/C<BC>/F5.txt",
"A<N1>/D<ADC>/C<DC>/F6.txt",
"A<N1>/D<ADC>/C<DC>/F7.txt",
}
DocIDs<string>=
{
"1",
"2",
"3",
"4",
"5",
"6",
"7"
}
List<string> Data, List<string> DocIDs;
List<TreeItem> Root = new List<TreeItem>();
TreeItem RootNode = new TreeItem();
for (int i = 0; i < Data.Count; ++i)
{
string Prev = "";
string Next = "";
TreeItem PreNode = new TreeItem();
TreeItem CurrentNode = new TreeItem();
CurrentNode = RootNode;
for (int j = 0; j < Data[i].Split('/').Length; ++j)
{
string BindText = Data[i].Split('/')[j];
string id = "";
string text = "";
if (i == 0 && j == 0)
{
text = BindText.Substring(0, BindText.IndexOf('<'));
id = ((BindText.Replace(text, "")).Replace("<",
"")).Replace(">", "");
CurrentNode = new TreeItem() { ID = id, Text = text };
RootNode = CurrentNode;
}
else if (j == 0)
{
CurrentNode = RootNode;
}
else if (BindText.Contains("."))
{
text = BindText;
CurrentNode.Items = new List<TreeItem>();
CurrentNode.Items.Add(new TreeItem() { UniqueID = id, Text = text, ID = DocIDs[i] });
}
else
{
text = BindText.Substring(0, BindText.IndexOf('<'));
//id = ((BindText.Replace(text, "")).Replace("<","")).Replace(">", "");
BindText = BindText.Remove(0, BindText.IndexOf('<'));
id = (BindText.Replace("<", "")).Replace(">", "");
if (CurrentNode.Items == null)
{
CurrentNode.Items = new List<TreeItem>();
}
if (CurrentNode.Items.Count(m => m.UniqueID == id) == 0)
{
PreNode = CurrentNode;
CurrentNode = new TreeItem() { UniqueID = id, Text = text, ID = DocIDs[i] };
//PreNode.Items = new List<TreeItem>();
PreNode.Items.Add(CurrentNode);
}
else
{
CurrentNode = CurrentNode.Items.Single(m => m.UniqueID == id);
}
}
}
}
Root.Add(RootNode);
return Root;
实现 Treeview 的步骤
请按照以下步骤操作
创建 TreeView 类
public class TreeItem
{
public string Text { get; set; }
public string ID { get; set; }
public string URL { get; set; }
public string UniqueID { get; set; }
public string DetailText { get; set; }
public List<TreeItem> Items { get; set; }
}
创建 TreeBinder 类
public class TreeBinder
{
private List<string> AssignUniqueValue(List<string> Data)
{
List<string> ResultData = new List<string>();
for (int i = 0; i < Data.Count; ++i)
{
string Result = "";
Data[i] = Data[i].Replace('\\', '/');
for (int j = 0; j < Data[i].Split('/').Length; ++j)
{
string BindText = Data[i].Split('/')[j];
if (j == 0)
{
BindText = BindText + "<12>";
Result = BindText;
}
else if (BindText.Contains("."))
{
Result = Result + "/" + BindText;
}
else
{
BindText = BindText + "<" + Data[i].Split('/')[j - 1].Substring(0, 1) +
"XZE" + BindText.Substring(0, 1) + ">";
Result = Result + "/" + BindText;
}
}
ResultData.Add(Result);
}
return ResultData;
}
private List<TreeItem> GenerateTreeViewBasedOnUniueData(List<string> Data, List<string> DocIDs)
{
List<TreeItem> Root = new List<TreeItem>();
TreeItem RootNode = new TreeItem();
for (int i = 0; i < Data.Count; ++i)
{
string Prev = "";
string Next = "";
TreeItem PreNode = new TreeItem();
TreeItem CurrentNode = new TreeItem();
CurrentNode = RootNode;
for (int j = 0; j < Data[i].Split('/').Length; ++j)
{
string BindText = Data[i].Split('/')[j];
string id = "";
string text = "";
if (i == 0 && j == 0)
{
text = BindText.Substring(0, BindText.IndexOf('<'));
id = ((BindText.Replace(text, "")).Replace
("<", "")).Replace(">", "");
CurrentNode = new TreeItem() { ID = id, Text = text };
RootNode = CurrentNode;
}
else if (j == 0)
{
CurrentNode = RootNode;
}
else if (BindText.Contains("."))
{
text = BindText;
CurrentNode.Items = new List<TreeItem>();
CurrentNode.Items.Add(new TreeItem() { UniqueID = id, Text = text, ID = DocIDs[i] });
}
else
{
text = BindText.Substring(0, BindText.IndexOf('<'));
//id = ((BindText.Replace(text, "")).Replace
//("<", "")).Replace(">", "");
BindText = BindText.Remove(0, BindText.IndexOf('<'));
id = (BindText.Replace("<", "")).Replace(">", "");
if (CurrentNode.Items == null)
{
CurrentNode.Items = new List<TreeItem>();
}
if (CurrentNode.Items.Count(m => m.UniqueID == id) == 0)
{
PreNode = CurrentNode;
CurrentNode = new TreeItem() { UniqueID = id, Text = text, ID = DocIDs[i] };
//PreNode.Items = new List<TreeItem>();
PreNode.Items.Add(CurrentNode);
}
else
{
CurrentNode = CurrentNode.Items.Single(m => m.UniqueID == id);
}
}
}
}
Root.Add(RootNode);
return Root;
在视图中声明 TreeView 控件
<script type="text/javascript">
function BindTreeView() {
console.log("start");
var url = '/NMA/LoadTree'//'@Url.Action("LoadTree", "NMA")';
$.post(url,
function (data) {
console.log(data);
$("#tree").igTree({
dataSource: data, //JSON Array defined above
bindings: {
textKey: "Text",
valueKey: "ID",
childDataProperty: "Items",
bindings: {
textKey: "Text",
valueKey: "ID"
}
}
});
});
}
</script>
<button type="button" value="test" onclick="BindTreeView();">Click me</button>
<ul id="tree"></ul>
从控制器调用 tree binder 方法
public JsonResult LoadTree()
{
string[] Data ={
"A/F1.txt",
"A/B/F2.txt",
"A/B/F3.txt",
"A/B/C/F4.txt",
"A/B/C/F5.txt",
"A/D/C/F6.txt",
"A/D/C/F7.txt"
};
string[] DocIDs ={
"1",
"2",
"3",
"4",
"5",
"6",
"7"
};
TreeBinder treObj = new TreeBinder();
List<TreeItem> tree = treObj.GenerateTreeView(Data.ToList(), DocIDs.ToList());
return Json(tree, JsonRequestBehavior.AllowGet);
}