TreeNode.cs 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. using System.ComponentModel;
  2. using System.Drawing;
  3. using System.Windows.Media;
  4. namespace System.Windows.Forms
  5. {
  6. public class TreeNode : INotifyPropertyChangedImpl
  7. {
  8. private TreeView owner;
  9. private string savedText;
  10. internal TreeView Owner => owner;
  11. public TreeNodeCollection Nodes { get; }
  12. public TreeNode Parent { get; private set; }
  13. public string Name { get; set; }
  14. private string text;
  15. public string Text
  16. {
  17. get => text;
  18. set => this.RaiseAndSetIfChanged(ref text, value);
  19. }
  20. private int imageIndex;
  21. public int ImageIndex
  22. {
  23. get => imageIndex;
  24. set
  25. {
  26. if (imageIndex != value)
  27. {
  28. imageIndex = value;
  29. ResetImageSource();
  30. }
  31. }
  32. }
  33. public int SelectedImageIndex
  34. {
  35. get => ImageIndex;
  36. set => ImageIndex = value;
  37. }
  38. private ImageSource imageSource;
  39. public ImageSource ImageSource
  40. {
  41. get
  42. {
  43. if (imageSource == null)
  44. {
  45. var imageList = owner?.ImageList;
  46. if (imageList != null && imageIndex >= 0 && imageIndex < imageList.Images.Count)
  47. imageSource = imageList.Images.ImageSources[imageIndex];
  48. }
  49. return imageSource;
  50. }
  51. }
  52. public int ImageSourceWidth => owner?.ImageList != null ? (int)(owner.ImageList.ImageSize.Width / owner.DpiScale) : 16;
  53. public int ImageSourceHeight => owner?.ImageList != null ? (int)(owner.ImageList.ImageSize.Height / owner.DpiScale) : 16;
  54. private bool? isChecked = false;
  55. [EditorBrowsable(EditorBrowsableState.Never)]
  56. public bool? IsChecked
  57. {
  58. get => isChecked;
  59. set
  60. {
  61. if (isChecked != value)
  62. {
  63. var args = new TreeViewCancelEventArgs(this, false, TreeViewAction.Unknown);
  64. owner?.DoBeforeCheck(args);
  65. if (!args.Cancel)
  66. {
  67. this.RaiseAndSetIfChanged(ref isChecked, value);
  68. var args1 = new TreeViewEventArgs(this);
  69. owner?.DoAfterCheck(args1);
  70. }
  71. }
  72. }
  73. }
  74. public bool Checked
  75. {
  76. get => IsChecked ?? false;
  77. set => IsChecked = value;
  78. }
  79. private bool isExpanded;
  80. public bool IsExpanded
  81. {
  82. get => isExpanded;
  83. set
  84. {
  85. if (isExpanded != value)
  86. {
  87. var args = new TreeViewCancelEventArgs(this, false, TreeViewAction.Unknown);
  88. if (isExpanded)
  89. owner?.DoBeforeCollapse(args);
  90. else
  91. owner?.DoBeforeExpand(args);
  92. if (!args.Cancel)
  93. {
  94. this.RaiseAndSetIfChanged(ref isExpanded, value);
  95. var args1 = new TreeViewEventArgs(this);
  96. if (isExpanded)
  97. owner?.DoAfterExpand(args1);
  98. else
  99. owner?.DoAfterCollapse(args1);
  100. }
  101. }
  102. }
  103. }
  104. private bool isSelected;
  105. public bool IsSelected
  106. {
  107. get => isSelected;
  108. set
  109. {
  110. if (isSelected != value)
  111. {
  112. if (value && owner != null)
  113. value = owner.DoNodeSelect(this);
  114. if (value)
  115. ExpandPath();
  116. this.RaiseAndSetIfChanged(ref isSelected, value);
  117. }
  118. }
  119. }
  120. private bool isEditing;
  121. public bool IsEditing
  122. {
  123. get => isEditing;
  124. set => this.RaiseAndSetIfChanged(ref isEditing, value);
  125. }
  126. private System.Drawing.Color backColor;
  127. public System.Drawing.Color BackColor
  128. {
  129. get => backColor;
  130. set
  131. {
  132. if (backColor != value)
  133. {
  134. backColor = value;
  135. backColorBrush = null;
  136. RaisePropertyChanged("BackColorBrush");
  137. }
  138. }
  139. }
  140. private System.Drawing.Color foreColor;
  141. public System.Drawing.Color ForeColor
  142. {
  143. get => foreColor;
  144. set
  145. {
  146. if (foreColor != value)
  147. {
  148. foreColor = value;
  149. foreColorBrush = null;
  150. RaisePropertyChanged("IsForeColorSet");
  151. RaisePropertyChanged("ForeColorBrush");
  152. }
  153. }
  154. }
  155. public System.Windows.Media.SolidColorBrush backColorBrush;
  156. [EditorBrowsable(EditorBrowsableState.Never)]
  157. public System.Windows.Media.SolidColorBrush BackColorBrush
  158. {
  159. get
  160. {
  161. if (backColorBrush == null)
  162. backColorBrush = new System.Windows.Media.SolidColorBrush(Helper.GetColor(BackColor));
  163. return backColorBrush;
  164. }
  165. }
  166. public System.Windows.Media.SolidColorBrush foreColorBrush;
  167. [EditorBrowsable(EditorBrowsableState.Never)]
  168. public System.Windows.Media.SolidColorBrush ForeColorBrush
  169. {
  170. get
  171. {
  172. if (foreColorBrush == null)
  173. foreColorBrush = new System.Windows.Media.SolidColorBrush(Helper.GetColor(ForeColor));
  174. return foreColorBrush;
  175. }
  176. }
  177. public string FullPath
  178. {
  179. get
  180. {
  181. if (owner == null)
  182. return null;
  183. var path = "";
  184. var item = this;
  185. while (item != null)
  186. {
  187. path = item.Text + (path == "" ? "" : owner.PathSeparator) + path;
  188. item = item.Parent;
  189. }
  190. return path;
  191. }
  192. }
  193. public int Index => (Parent == null ? owner.Nodes : Parent.Nodes).IndexOf(this);
  194. public TreeNode NextNode
  195. {
  196. get
  197. {
  198. var nodes = Parent == null ? owner.Nodes : Parent.Nodes;
  199. var index = Index;
  200. if (index + 1 < nodes.Count)
  201. return nodes[index + 1];
  202. return null;
  203. }
  204. }
  205. public TreeNode PrevNode
  206. {
  207. get
  208. {
  209. var nodes = Parent == null ? owner.Nodes : Parent.Nodes;
  210. var index = Index;
  211. if (index - 1 >= 0)
  212. return nodes[index - 1];
  213. return null;
  214. }
  215. }
  216. public object Tag { get; set; }
  217. private Rectangle bounds;
  218. public Rectangle Bounds => bounds; // TODO: FIXME all use cases
  219. internal void SetBounds(Rectangle bounds) => this.bounds = bounds;
  220. private void ExpandPath()
  221. {
  222. var parent = Parent;
  223. while (parent != null)
  224. {
  225. parent.IsExpanded = true;
  226. parent = parent.Parent;
  227. }
  228. }
  229. internal void SetOwner(TreeView owner)
  230. {
  231. this.owner = owner;
  232. Nodes.SetOwner(owner);
  233. }
  234. internal void SetParent(TreeNode parent) => Parent = parent;
  235. internal void ResetImageSource()
  236. {
  237. imageSource = null;
  238. RaisePropertyChanged("ImageSource");
  239. RaisePropertyChanged("ImageSourceWidth");
  240. RaisePropertyChanged("ImageSourceHeight");
  241. }
  242. internal void ResetImageSourceAll()
  243. {
  244. ResetImageSource();
  245. for (int i = 0; i < Nodes.Count; i++)
  246. Nodes[i].ResetImageSourceAll();
  247. }
  248. public void Expand() => IsExpanded = true;
  249. public void Collapse() => IsExpanded = false;
  250. public void ExpandAll()
  251. {
  252. Expand();
  253. for (int i = 0; i < Nodes.Count; i++)
  254. Nodes[i].ExpandAll();
  255. }
  256. public void CollapseAll()
  257. {
  258. Collapse();
  259. for (int i = 0; i < Nodes.Count; i++)
  260. Nodes[i].CollapseAll();
  261. }
  262. public void BeginEdit()
  263. {
  264. var args = new NodeLabelEditEventArgs(this);
  265. owner.DoOnBeforeLabelEdit(args);
  266. if (!args.CancelEdit)
  267. {
  268. savedText = Text;
  269. IsEditing = true;
  270. owner.SetEditedNode(this);
  271. }
  272. }
  273. public void EndEdit(bool cancel)
  274. {
  275. var args = new NodeLabelEditEventArgs(this, cancel ? null : Text);
  276. // in WinForms OnAfterLabelEdit the node.Text has old value
  277. Text = savedText;
  278. owner.DoOnAfterLabelEdit(args);
  279. if (args.CancelEdit)
  280. cancel = true;
  281. IsEditing = false;
  282. if (!cancel)
  283. Text = args.Label;
  284. owner.SetEditedNode(null);
  285. }
  286. public void Remove()
  287. {
  288. if (Parent != null)
  289. Parent.Nodes.Remove(this);
  290. else
  291. owner.Nodes.Remove(this);
  292. }
  293. public TreeNode()
  294. {
  295. Nodes = new(this);
  296. backColor = Drawing.SystemColors.Window;
  297. foreColor = Drawing.SystemColors.WindowText;
  298. }
  299. public TreeNode(string text) : this()
  300. {
  301. Text = text;
  302. }
  303. public TreeNode(string text, TreeNode[] nodes) : this(text)
  304. {
  305. foreach (var node in nodes)
  306. Nodes.Add(node);
  307. }
  308. }
  309. }