我正在使用VS 2005 C#,处理未完成的WinForm。
我已经将XML解析为树视图列表,但我遇到了一些问题。 我想知道是否有办法隐藏/过滤/删除名称中包含“_this_text”的某个节点,而不必依赖文本框。
这就是我对该计划的看法(对那些帮助我开发此项目的人的称赞):
#region "***** XML Parsing *****"
private void Form1_Load_1(object sender, EventArgs e)
{
// Initialize the controls and the form.
//label1.Text = "File Path";
textBox2.Text = Application.StartupPath + "\\Continental.vsysvar";
//button6.Text = "XML";
//this.Text = "Software Validation";
}
private TreeNode selectedNode = null;
private void button6_Click(object sender, EventArgs e)
{
try
{
// SECTION 1. Create a DOM Document and load the XML data into it.
XmlDocument dom = new XmlDocument();
dom.Load(textBox2.Text);
// SECTION 2. Initialize the TreeView control.
treeView1.Nodes.Clear();
/*treeView1.Nodes.Add(new TreeNode(dom.DocumentElement.Name));
TreeNode tNode = new TreeNode();
tNode = treeView1.Nodes[0];*/
foreach (XmlNode node in dom.DocumentElement.ChildNodes)
{
if (node.Name == "namespace" && node.ChildNodes.Count == 0 && string.IsNullOrEmpty(GetAttributeText(node, "name")))
continue;
AddNode(treeView1.Nodes, node);
}
treeView1.ExpandAll();
}
/* catch (XmlException xmlEx)
{
MessageBox.Show(xmlEx.Message);
}*/
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void LoadTreeFromXmlDocument(XmlDocument dom)
{
try
{
// SECTION 2. Initialize the TreeView control.
treeView1.Nodes.Clear();
// SECTION 3. Populate the TreeView with the DOM nodes.
foreach (XmlNode node in dom.DocumentElement.ChildNodes)
{
if (node.Name == "namespace" && node.ChildNodes.Count == 0 && string.IsNullOrEmpty(GetAttributeText(node, "name")))
continue;
AddNode(treeView1.Nodes, node);
}
treeView1.ExpandAll();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
static string GetAttributeText(XmlNode inXmlNode, string name)
{
XmlAttribute attr = (inXmlNode.Attributes == null ? null : inXmlNode.Attributes[name]);
return attr == null ? null : attr.Value;
}
private void AddNode(TreeNodeCollection nodes, XmlNode inXmlNode)
{
if (inXmlNode.HasChildNodes)
{
string text = GetAttributeText(inXmlNode, "name");
if (string.IsNullOrEmpty(text))
text = inXmlNode.Name;
TreeNode newNode = nodes.Add(text);
XmlNodeList nodeList = inXmlNode.ChildNodes;
for (int i = 0; i <= nodeList.Count - 1; i++)
{
XmlNode xNode = inXmlNode.ChildNodes[i];
AddNode(newNode.Nodes, xNode);
}
}
else
{
// If the node has an attribute "name", use that. Otherwise display the entire text of the node.
string text = GetAttributeText(inXmlNode, "name");
if (string.IsNullOrEmpty(text))
text = (inXmlNode.OuterXml).Trim();
TreeNode newNode = nodes.Add(text);
}
}
#endregion
这里是XMl文件的摘录,因为它很长:
<?xml version="1.0" encoding="utf-8"?>
<systemvariables version="4">
<namespace name="" comment="">
<namespace name="_01_Test_Preparation" comment="">
<variable anlyzLocal="2" readOnly="false" valueSequence="false" unit="" name="_01_02_Shipping_Status_Check" comment="" bitcount="32" isSigned="true" encoding="65001" type="int" startValue="0" minValue="0" minValuePhys="0" maxValue="4" maxValuePhys="4" />
<variable anlyzLocal="2" readOnly="false" valueSequence="false" unit="" name="_01_02_Shipping_Status_Check_start" comment="" bitcount="32" isSigned="true" encoding="65001" type="int" startValue="0" minValue="0" minValuePhys="0" maxValue="4" maxValuePhys="4" />
<variable anlyzLocal="2" readOnly="false" valueSequence="false" unit="" name="_01_01_Get_Dem_ID" comment="" bitcount="32" isSigned="true" encoding="65001" type="int" startValue="0" minValue="0" minValuePhys="0" maxValue="4" maxValuePhys="4" />
<variable anlyzLocal="2" readOnly="false" valueSequence="false" unit="" name="_01_01_Get_Dem_ID_start" comment="" bitcount="32" isSigned="true" encoding="65001" type="int" startValue="0" minValue="0" minValuePhys="0" maxValue="4" maxValuePhys="4" />
<variable anlyzLocal="2" readOnly="false" valueSequence="false" unit="" name="_01_04_ECU_Version_Check_start" comment="" bitcount="32" isSigned="true" encoding="65001" type="int" startValue="0" minValue="0" minValuePhys="0" maxValue="4" maxValuePhys="4" />
<variable anlyzLocal="2" readOnly="false" valueSequence="false" unit="" name="_01_03_Test_Run_Init" comment="" bitcount="32" isSigned="true" encoding="65001" type="int" startValue="0" minValue="0" minValuePhys="0" maxValue="4" maxValuePhys="4" />
<variable anlyzLocal="2" readOnly="false" valueSequence="false" unit="" name="_01_04_ECU_Version_Check" comment="" bitcount="32" isSigned="true" encoding="65001" type="int" startValue="0" minValue="0" minValuePhys="0" maxValue="4" maxValuePhys="4" />
<variable anlyzLocal="2" readOnly="false" valueSequence="false" unit="" name="_01_05_DEM_Reader" comment="" bitcount="32" isSigned="true" encoding="65001" type="int" startValue="0" minValue="0" minValuePhys="0" maxValue="4" maxValuePhys="4" />
<variable anlyzLocal="2" readOnly="false" valueSequence="false" unit="" name="_01_03_Test_Run_Init_start" comment="" bitcount="32" isSigned="true" encoding="65001" type="int" startValue="0" minValue="0" minValuePhys="0" maxValue="4" maxValuePhys="4" />
<variable anlyzLocal="2" readOnly="false" valueSequence="false" unit="" name="_01_05_DEM_Reader_start" comment="" bitcount="32" isSigned="true" encoding="65001" type="int" startValue="0" minValue="0" minValuePhys="0" maxValue="4" maxValuePhys="4" />
</namespace>
我真正想要实现的是隐藏或过滤包含其名称中的“_start”文本的节点。因此,名称中包含“_this_start”的所有节点都将对用户隐藏。我已经读过,技术上不可能启用或禁用可见性,而是灰显文本等等。
提前谢谢。
答案 0 :(得分:1)
从您的问题中不清楚过滤器是静态的还是可由用户配置。假设可以动态配置过滤器,您可以做的是每当过滤器更改时重新加载树,回收现有节点,根据需要创建新节点,以及删除过滤后的节点。 (当然,如果过滤器是静态的,这也有效。)
首先,提取辅助方法以从XML重新填充树,在适当的时候按名称回收节点:
public delegate string GetString<T>(T input); // No Func<T, TResult> in c# 2.0
public static class XmlTreeViewHelper
{
public static void AddOrMergeNodes(TreeNodeCollection treeNodeCollection, XmlNodeList xmlNodeList, GetString<XmlNode> getNodeName, GetString<XmlNode> getNodeText, Predicate<XmlNode> filter)
{
Dictionary<string, List<TreeNode>> dict = ToNodeDictionary(treeNodeCollection);
int index = 0;
foreach (XmlNode inXmlNode in xmlNodeList)
{
AddOrMergeNode(treeNodeCollection, inXmlNode, ref index, getNodeName, getNodeText, filter, dict);
}
foreach (List<TreeNode> list in dict.Values)
foreach (TreeNode leftover in list)
{
treeNodeCollection.Remove(leftover);
}
}
static bool IsNodeAtIndex(TreeNodeCollection nodes, TreeNode node, int index)
{
// Avoid n-squared nodes.IndexOf(node).
if (index < 0 || index >= nodes.Count)
return false;
return nodes[index] == node;
}
static void AddOrMergeNode(TreeNodeCollection treeNodeCollection, XmlNode inXmlNode, ref int index, GetString<XmlNode> getNodeName, GetString<XmlNode> getNodeText, Predicate<XmlNode> filter, Dictionary<string, List<TreeNode>> dict)
{
if (filter != null && !filter(inXmlNode))
return;
string treeName = getNodeName(inXmlNode);
string treeText = (getNodeText == null ? treeName : getNodeText(inXmlNode));
bool added = false;
TreeNode treeNode;
if (!DictionaryExtensions.TryRemoveFirst(dict, treeName, out treeNode))
{
treeNode = new TreeNode();
treeNode.Name = treeName;
treeNode.Text = treeText;
added = true;
treeNodeCollection.Insert(index, treeNode);
}
else
{
if (!IsNodeAtIndex(treeNodeCollection, treeNode, index))
{
treeNodeCollection.Remove(treeNode);
treeNodeCollection.Insert(index, treeNode);
}
}
index++;
if (treeNode.Text != treeText)
treeNode.Text = treeText;
if (inXmlNode.HasChildNodes)
AddOrMergeNodes(treeNode.Nodes, inXmlNode.ChildNodes, getNodeName, getNodeText, filter);
else
treeNode.Nodes.Clear();
if (added)
treeNode.ExpandAll();
}
/// <summary>
/// Returns a dictionary of tree nodes by node name.
/// </summary>
/// <param name="nodes"></param>
/// <returns></returns>
static Dictionary<string, List<TreeNode>> ToNodeDictionary(TreeNodeCollection nodes)
{
Dictionary<string, List<TreeNode>> dict = new Dictionary<string, List<TreeNode>>();
foreach (TreeNode node in nodes)
DictionaryExtensions.Add(dict, node.Name, node);
return dict;
}
}
public static class DictionaryExtensions
{
public static void Add<TKey, TValueList, TValue>(IDictionary<TKey, TValueList> listDictionary, TKey key, TValue value)
where TValueList : IList<TValue>, new()
{
if (listDictionary == null)
throw new ArgumentNullException();
TValueList values;
if (!listDictionary.TryGetValue(key, out values))
listDictionary[key] = values = new TValueList();
values.Add(value);
}
public static bool TryGetValue<TKey, TValueList, TValue>(IDictionary<TKey, TValueList> listDictionary, TKey key, int index, out TValue value)
where TValueList : IList<TValue>
{
TValueList list;
if (!listDictionary.TryGetValue(key, out list))
return Returns.False(out value);
if (index < 0 || index >= list.Count)
return Returns.False(out value);
value = list[index];
return true;
}
public static bool TryRemoveFirst<TKey, TValueList, TValue>(IDictionary<TKey, TValueList> listDictionary, TKey key, out TValue value)
where TValueList : IList<TValue>
{
TValueList list;
if (!listDictionary.TryGetValue(key, out list))
return Returns.False(out value);
int count = list.Count;
if (count > 0)
{
value = list[0];
list.RemoveAt(0);
if (--count == 0)
listDictionary.Remove(key);
return true;
}
else
{
listDictionary.Remove(key); // Error?
return Returns.False(out value);
}
}
}
public static class Returns
{
public static bool False<TValue>(out TValue value)
{
value = default(TValue);
return false;
}
}
接下来,动态(重新)加载XML并应用适当的过滤器:
private void ReloadTreeFromXmlDocument(XmlDocument dom)
{
treeView1.BeginUpdate();
try
{
XmlTreeViewHelper.AddOrMergeNodes(treeView1.Nodes, dom.DocumentElement.ChildNodes, GetTreeNodeName, GetTreeNodeText, FilterNode);
}
finally
{
treeView1.EndUpdate();
}
}
static string GetTreeNodeName(XmlNode inXmlNode)
{
string text = GetAttributeText(inXmlNode, "name");
if (string.IsNullOrEmpty(text))
text = inXmlNode.Name;
return text;
}
static string GetTreeNodeText(XmlNode inXmlNode)
{
string text = GetAttributeText(inXmlNode, "name");
if (string.IsNullOrEmpty(text))
{
if (inXmlNode.HasChildNodes)
{
text = inXmlNode.Name;
}
else
{
text = (inXmlNode.OuterXml).Trim();
}
}
return text;
}
string filter = "_start"; // Reload when this changes
bool FilterNode(XmlNode inXmlNode)
{
return FilterNode(inXmlNode, filter /*filterComboBox.Text*/);
}
bool FilterNode(XmlNode inXmlNode, string nodeNameFilter)
{
if (inXmlNode.Name == "namespace" && inXmlNode.ChildNodes.Count == 0 && string.IsNullOrEmpty(GetAttributeText(inXmlNode, "name")))
return false;
if (!string.IsNullOrEmpty(nodeNameFilter))
{
string text = GetTreeNodeText(inXmlNode);
if (text.Contains(nodeNameFilter))
return false;
}
return true;
}
static string GetAttributeText(XmlNode inXmlNode, string name)
{
XmlAttribute attr = (inXmlNode.Attributes == null ? null : inXmlNode.Attributes[name]);
return attr == null ? null : attr.Value;
}
将我的解决方案向后移植到.Net 2.0后,这就是我得到的: