问题
I am creating a tree by parsing a string separated by (.)
Edit:
public class TestElement{
public int Id { get; set; }
public string Name { get; set; }
public string Path { get; set; }
public List<TestElement> Children { get; set; }
public TestElement CurrentNode { get; set; }
public TestElement Parent { get; set; }
}
In TestElement For example I have this data:
public List<TestElement> GetTreeNodes()
{
var nodeElements = new List<TestElement>();
AddNode(nodeElements, 1, "a.b.c.value");
AddNode(nodeElements, 2, "a.c.f.g");
return nodeElements;
}
Parsing :
private void AddNode(List<TestElement> nodes, int id, string path)
{
AddNode(nodes, id, path.Split('.'));
}
Here I am looping thru the parsed strings and assign them the unique Id. I am assigning ID to the last element in the path so that I can uniquely identify each path.
private void AddNode(List<TestElement> nodes, int id, params string[] path)
{
CurrentNode =null;
foreach (var name in path)
{
var currentCollection = (CurrentNode != null ? CurrentNode.Children : nodes);
var thisNode = currentCollection.FirstOrDefault(n => n.Name == name);
if (thisNode == null)
{
thisNode = new TestElement { Name = name };
currentCollection.Add(thisNode);
}
CurrentNode = thisNode;
}
if (CurrentNode != null)
CurrentNode.Id = id;
}
I have a grid with the following data:
TestField.Add(new TestField(1, "ABCD",5, 4));
TestField.Add(new TestField(2, "EFGH", 9, 7));
In my ViewModel here is how am doing the comparison between the grid and treenode id
public void SearchTree(int id, List<TestElement> nodes)
{
foreach (var c in nodes)
{
if (c.id == id)
{
c.DisplayColor = Brushes.Violet;
}
else
{
c.DisplayColor = Brushes.Black;
}
SearchTree(id, c.Children);
}
}
What I want to do is create a relationship in my WPF application. When I click the TestField with id=1 I want to associate it to my tree node(TestElement) with id number =1 Right now it is associating it to the last element only. How can I associate it to the whole path? so that I can Highlight it with some color.
New Edit:
TestElementViewModel:
public TestElement Parent { get; set; }
public void HighlightNode(TestElementViewModel node)
{
for (var n = node; n != null; n = n.Parent)
{
DisplayColor = Brushes.Violet;
}
}
Recursivly building tree:
public IEnumerable<TestElementViewModel> ToTreeViewModel(IEnumerable<TestElement> treemodel)
{
return treemodel.Select(item => new TestElementViewModel { Id = item.Id, Name = item.Name, Children = ToTreeViewModel(item.Children).ToList(), Parent=item.Parent });
}
public List<TestElementViewModel> GetRequestTreeNodesFromModel()
{
return ToTreeViewModel(TreeModel.GetRequestTreeNodes()).ToList();
}
MainViewModel: This is a container of all my modelviews...
public TestElementViewModel SearchTree(int id, List<TestElementViewModel> nodes)
{
foreach (var c in nodes)
{
if (c.Id == id)
return c;
var n = SearchTree(id, c.Children);
if (n != null)
TestElementViewModelVModel.HighlightNode(n);
return n;
}
return null;
}
private void HighlightNode(MessageElementViewModel node)
{
for (var n = node; n != null; n = n.Parent)
{
n.DisplayColor = Brushes.Violet;
}
}
回答1:
I can think of two ways to do this:
1) Instead of having just an ID property for each node, have a Ids collection. This may use a substantial amount of memory when dealing with large numbers of nodes due to the extra collection being allocated for each node.
public class TestElement
{
/*NOTE:*/ public HashSet<int> Ids { get { return _ids ?? (_ids = new HashSet<int>()); } }
/*NOTE:*/ private HashSet<int> _ids;
...
}
private void AddNode(List<TestElement> nodes, int id, params string[] path)
{
CurrentNode = null;
foreach (var name in path)
{
var currentCollection = (CurrentNode != null ? CurrentNode.Children : nodes);
var thisNode = currentCollection.FirstOrDefault(n => n.Name == name);
if (thisNode == null)
{
thisNode = new TestElement { Name = name };
currentCollection.Add(thisNode);
}
/*NOTE:*/ thisNode.Ids.Add(id);
CurrentNode = thisNode;
}
}
private void SearchTree(int id, List<TestElement> nodes)
{
foreach (var c in nodes)
{
/*NOTE:*/ if (c.Ids.Contains(id))
{
c.DisplayColor = Brushes.Violet;
}
else
{
c.DisplayColor = Brushes.Black;
}
SearchTree(id, c.Children);
}
}
2) Keep only a single ID per node and let each node be aware of its parent. When you find the node that has the ID you're looking for, use the Parent property to walk up the tree to assign the properties to ancestor nodes.
public class TestElement
{
/*NOTE:*/ public int ID { get; set; }
/*NOTE:*/ public TestElement Parent { get; set; }
...
}
private void AddNode(List<TestElement> nodes, int id, params string[] path)
{
CurrentNode = null;
foreach (var name in path)
{
var currentCollection = (CurrentNode != null ? CurrentNode.Children : nodes);
var thisNode = currentCollection.FirstOrDefault(n => n.Name == name);
if (thisNode == null)
{
thisNode = new TestElement { Name = name, /*NOTE:*/ Parent = CurrentNode };
currentCollection.Add(thisNode);
}
CurrentNode = thisNode;
}
if (CurrentNode != null)
CurrentNode.Id = id;
}
private TestElement FindNode(int id, List<TestElement> nodes)
{
foreach (var c in nodes)
{
if (c.ID == id)
return c;
var n = FindNode(id, c.Children);
if (n != null)
return n;
}
return null;
}
private void HighlightNode(TestElement node)
{
for (var n = node; n != null; n = n.Parent)
n.DisplayColor = Brushes.Violet;
}
来源:https://stackoverflow.com/questions/17068886/wpf-associating-grid-selected-element-with-unique-treenode