This article references
Author: SmlAnt
Source: http://www.cnblogs.com/smlAnt
Note: Please retain the above content and indicate the author and source when reprinting.

The article contains many useful knowledge points.
When making functional requirements, the Treeview command is needed, and in the production process, it was found that the hierarchical structure of TreeView conforms to the hierarchical structure of Revit, which can make the data display more clearly.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
public class TreeNode : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;

/// <summary>
/// Listen directly to property change events
/// </summary>
/// <param name="info"></param>
private void NotifyProperChanged(string info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}

#region Basic Data

public double ParentId { get; set; }
public string ElementName { get; set; }
public double Id { get; set; }
public ElementId ElementId { get; set; }
private bool? _IsChecked;

/// <summary>
/// ParentNode
/// </summary>
public TreeNode Parent { get; set; }

#endregion

/// <summary>
/// Constructor
/// </summary>
public TreeNode(List<TreeNode> Nodes)
{
_IsChecked = false;
ParentNodes = GetChildNodes(0, Nodes);
}

public TreeNode()
{
_IsChecked = false;
}

/// <summary>
/// create a ChildNode
/// </summary>
public List<TreeNode> ChildrenNode { get; set; }


/// <summary>
/// IsSelected
/// </summary>
public bool? IsChecked
{
get { return _IsChecked; }
set
{
if (value != _IsChecked)
{
_IsChecked = value;
if (IsChecked == true)
{
ChangeChildNodes(this);
ChangeParentNodes(this);
NotifyProperChanged("IsChecked");
}


}
}
}

/// <summary>
/// Set Select All
/// </summary>
/// <param name="isChecked"></param>
public void SetChildrenChecked(bool? isChecked)
{
foreach (TreeNode child in ChildrenNode)
{
child.IsChecked = IsChecked;
child.SetChildrenChecked(IsChecked);
}
}

private List<TreeNode> parentNodes = new List<TreeNode>();

public List<TreeNode> ParentNodes
{
get { return parentNodes; }
set
{
parentNodes = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("ParentNodes"));
}
}
/// <summary>
/// Recursive algorithm to get tree data
/// </summary>
/// <param name="parenId"></param>
/// <param name="nodels"></param>
/// <returns></returns>
private List<TreeNode> GetChildNodes(double parenId, List<TreeNode> nodels)
{
List<TreeNode> mainDatas = nodels.Where(t => t.ParentId == parenId).ToList<TreeNode>();
List<TreeNode> secondDatas = nodels.Where(t => t.ParentId != parenId).ToList<TreeNode>();
foreach (TreeNode fd in mainDatas)
{
fd.ChildrenNode = GetChildNodes(fd.Id, secondDatas);
}

return mainDatas;
}

private void ChangeChildNodes(TreeNode treeNode)
{
if (treeNode.ChildrenNode != null)
{
foreach (var data in treeNode.ChildrenNode)
{
data.IsChecked = true;
data.NotifyProperChanged("IsChecked");
if (data.ChildrenNode != null)
{
data.ChangeChildNodes(data);
}
}
}
}
/// <summary>
/// Traverse downwards, change child node status
/// </summary>
/// <param name="treeNode"></param>
public void ChangeParentNodes(TreeNode treeNode)
{
if (treeNode.Parent != null)
{
bool? parentChecked = true;
int selectedCount = 0;//Selected count
int noSelectedCount = 0;//Unselected count
foreach (var data in treeNode.Parent.ChildrenNode)
{
if (data.IsChecked == true)
{
selectedCount++;
}
else if (data.IsChecked == false)
{
noSelectedCount++;
}
}

//If all selected, then parent node is selected
if (selectedCount == treeNode.Parent.ChildrenNode.Count)
{
parentChecked = true;
}
else if (noSelectedCount == treeNode.Parent.ChildrenNode.Count)
{
parentChecked = false;
}
else
{
parentChecked = null;
}

treeNode.Parent.IsChecked = parentChecked;
treeNode.Parent.NotifyProperChanged("IsChecked");
if (treeNode.Parent.Parent != null)
{
ChangeParentNodes(treeNode.Parent);
}
}
}

}

The recursion part and top-down code are still not very well understood, will study carefully later!