我必须在WinForm中显示一个基于复杂字典的TreeView,我正在寻找“最短”的方法来实现它。我认为它可以在一个LINQ查询中完成,但我不知道如何,我甚至不确定它是否可能。
这是一个输入字典的例子:
Dictionary<String, String> dict = new Dictionary<String, String>()
{
{"aaa.bbb.ccc.ddd", "value1"},
{"aaa.bbb.ccc.eee", "value2"},
{"aaa.bbb.fff.ggg", "value3"},
{"aaa.hhh.iii.jjj", "value4"},
{"bbb.ddd", "value5"},
{"ccc", "value6"}
};
我想回到这样的TreeView:
|--+ aaa
| |--+ bbb
| | |--+ ccc
| | | |--- ddd = value1
| | | |--- eee = value2
| | |
| | |--+ fff
| | | |--- ggg = value3
| |
| |--+ hhh
| | |--+ iii
| | | |--- jjj = value4
|
|--+ bbb
| |--- ddd = value5
|
|--+ ccc = value6
这就是我现在所拥有的(我还没有处理价值):
List<String> list = new List<string>() {
"aaa.bbb.ccc.ddd",
"aaa.bbb.ccc.eee",
"aaa.bbb.fff.ddd",
"aaa.bbb.fff.ggg",
"aaa.ggg.fff.hhh",
"hhh.iii.jjj.kkk"
};
Action<TreeNode, String> traverse = null;
traverse = (node, chaine) =>
{
String[] tab = chaine.Split(new char[] { '.' }, 2);
TreeNode child = null;
if (node.Nodes.ContainsKey(tab[0]))
{
child = node.Nodes[tab[0]];
}
else
{
child = node.Nodes.Add(tab[0]); // + ((tab.Length > 1) ? " - " + tab[1] : ""));
child.Name = tab[0];
}
if (tab.Length > 1 && !String.IsNullOrEmpty(tab[1]))
traverse(child, tab[1]);
};
TreeNode test = this.treeView1.Nodes.Add("test");
list.ForEach(x => traverse(test, x));
我希望我的解释清楚。
答案 0 :(得分:1)
你的Action中有相当多的逻辑,所以我怀疑它可以在一个LINQ查询中完成,所以它看起来像
var query = from this in that
where this is t
select this
但你可以做的是重写一下,例如:
public void AnotherWay()
{
TreeNode parent = this.treeView1.Nodes.Add("test");
List<String> list = new List<String>()
{
"aaa.bbb.ccc.ddd",
"aaa.bbb.ccc.eee",
"aaa.bbb.fff.ddd",
"aaa.bbb.fff.ggg",
"aaa.ggg.fff.hhh",
"hhh.iii.jjj.kkk"
};
list.ForEach(x =>
{
TreeNode root = parent;
TreeNode child = null;
x.Split(new[] { '.' })
.ToList()
.ForEach(i =>
{
child = root.Nodes.ContainsKey(i) ?
root.Nodes[i] :
root.Nodes.Add(i);
child.Name = i;
root = child;
});
});
}
此代码完全按照您已发布的内容执行,但只是更小,IMO读取的内容稍微清晰。
通常我会看到一个Action或Func执行一些逻辑来成为代码气味,特别是如果它被重复使用多次(在这种情况下它应该被提取到它自己的方法中,但是我离题)。
在你的情况下,虽然看起来Action仅在行list.ForEach(x => traverse(test, x));
中使用了一次,因此功能可以简单地替换你对Action的调用,如上例所示。
(但是,如果逻辑或LOC的复杂性增加,那么在这个例子中,我很想将功能移到它自己的可维护性方法中。)
这种方法还可以让您轻松满足处理字典的第二个要求,只需稍加修改,例如:
public void DictFunc()
{
TreeNode parent = this.treeView1.Nodes.Add("test");
Dictionary<String, String> dict = new Dictionary<String, String>()
{
{ "aaa.bbb.ccc.ddd", "Value1" },
{ "aaa.bbb.ccc.eee", "Value2" },
{ "aaa.bbb.fff.ddd", "Value3" },
{ "aaa.bbb.fff.ggg", "Value4" },
{ "aaa.ggg.fff.hhh", "Value5" },
{ "hhh.iii.jjj.kkk", "Value6" }
};
dict.ToList().ForEach(x =>
{
// For brevity, same as logic in example above.
// Plus the small amount (~three LOC) of additional logic
// required to handle the values.
});
}
我已将字典值处理作为练习留给您,但ForEach
内的其余逻辑与我的第一个示例中的逻辑相同。