经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C# » 查看文章
Winform组合ComboBox和TreeView实现ComboTree
来源:cnblogs  作者:飞·羽  时间:2019/9/26 11:16:32  对本文有异议

最近做Winform项目需要用到类似ComboBox的TreeView控件。

虽然各种第三方控件很多,但是存在各种版本不兼容问题。所以自己写了个简单的ComboTreeView控件。

下图是实现效果:

 

目前实现的比较简单,能满足我项目中的需求。

此处是项目中的代码简化后的版本,供大家参考。

  1. 1 using System;
  2. 2 using System.Collections.Generic;
  3. 3 using System.Windows.Forms;
  4. 4
  5. 5 namespace CustomControl.Tree
  6. 6 {
  7. 7 public abstract class ComboTreeView<T> : ComboBox where T : class
  8. 8 {
  9. 9 protected const int WM_LBUTTONDOWN = 0x0201, WM_LBUTTONDBLCLK = 0x0203;
  10. 10
  11. 11 protected TreeView treeView;
  12. 12 protected ToolStripControlHost treeViewHost;
  13. 13 protected ToolStripDropDown dropDown;
  14. 14 protected bool dropDownOpen = false;
  15. 15 protected TreeNode selectedNode;
  16. 16 protected T selectedNodeData;
  17. 17 protected T toBeSelected;
  18. 18
  19. 19 public ComboTreeView(TreeView internalTreeView)
  20. 20 {
  21. 21 if (null == internalTreeView)
  22. 22 {
  23. 23 throw new ArgumentNullException("internalTreeView");
  24. 24 }
  25. 25 this.InitializeControls(internalTreeView);
  26. 26 }
  27. 27
  28. 28 public event TreeNodeChangedEventHandler TreeNodeChanged;
  29. 29
  30. 30 protected virtual void InitializeControls(TreeView internalTreeView)
  31. 31 {
  32. 32 this.treeView = internalTreeView;
  33. 33 this.treeView.BorderStyle = BorderStyle.FixedSingle;
  34. 34 this.treeView.Margin = new Padding(0);
  35. 35 this.treeView.Padding = new Padding(0);
  36. 36 this.treeView.AfterExpand += new TreeViewEventHandler(this.WhenAfterExpand);
  37. 37
  38. 38 this.treeViewHost = new ToolStripControlHost(this.treeView);
  39. 39 this.treeViewHost.Margin = new Padding(0);
  40. 40 this.treeViewHost.Padding = new Padding(0);
  41. 41 this.treeViewHost.AutoSize = false;
  42. 42
  43. 43 this.dropDown = new ToolStripDropDown();
  44. 44 this.dropDown.Margin = new Padding(0);
  45. 45 this.dropDown.Padding = new Padding(0);
  46. 46 this.dropDown.AutoSize = false;
  47. 47 this.dropDown.DropShadowEnabled = true;
  48. 48 this.dropDown.Items.Add(this.treeViewHost);
  49. 49 this.dropDown.Closed += new ToolStripDropDownClosedEventHandler(this.OnDropDownClosed);
  50. 50
  51. 51 this.DropDownWidth = this.Width;
  52. 52 base.DropDownStyle = ComboBoxStyle.DropDownList;
  53. 53 base.SizeChanged += new EventHandler(this.WhenComboboxSizeChanged);
  54. 54 }
  55. 55
  56. 56 public new ComboBoxStyle DropDownStyle
  57. 57 {
  58. 58 get { return base.DropDownStyle; }
  59. 59 set { base.DropDownStyle = ComboBoxStyle.DropDownList; }
  60. 60 }
  61. 61
  62. 62 public virtual TreeNode SelectedNode
  63. 63 {
  64. 64 get { return this.selectedNode; }
  65. 65 private set { this.treeView.SelectedNode = value; }
  66. 66 }
  67. 67
  68. 68 public virtual T SelectedNodeData
  69. 69 {
  70. 70 get { return this.selectedNodeData; }
  71. 71 set
  72. 72 {
  73. 73 this.selectedNodeData = value;
  74. 74 this.toBeSelected = value;
  75. 75 this.UpdateComboBox(value);
  76. 76 }
  77. 77 }
  78. 78
  79. 79 protected new int SelectedIndex
  80. 80 {
  81. 81 get { return base.SelectedIndex; }
  82. 82 set { base.SelectedIndex = value; }
  83. 83 }
  84. 84
  85. 85 protected new object SelectedItem
  86. 86 {
  87. 87 get { return base.SelectedItem; }
  88. 88 set { base.SelectedItem = value; }
  89. 89 }
  90. 90
  91. 91 public virtual string DisplayMember { get; set; } = "Name";
  92. 92
  93. 93 /// <summary>Gets the internal TreeView control.</summary>
  94. 94 public virtual TreeView TreeView => this.treeView;
  95. 95
  96. 96 /// <summary>Gets the collection of tree nodes that are assigned to the tree view control.</summary>
  97. 97 /// <returns>A <see cref="T:System.Windows.Forms.TreeNodeCollection" /> that represents the tree nodes assigned to the tree view control.</returns>
  98. 98 public virtual TreeNodeCollection Nodes => this.treeView.Nodes;
  99. 99
  100. 100 public new int DropDownHeight { get; set; } = 100;
  101. 101
  102. 102 public new int DropDownWidth { get; set; } = 100;
  103. 103
  104. 104 protected virtual void ShowDropDown()
  105. 105 {
  106. 106 this.dropDown.Width = this.Width;
  107. 107 this.dropDown.Height = this.DropDownHeight;
  108. 108 this.treeViewHost.Width = this.Width;
  109. 109 this.treeViewHost.Height = this.DropDownHeight;
  110. 110 this.treeView.Font = this.Font;
  111. 111 this.dropDown.Focus();
  112. 112 this.dropDownOpen = true;
  113. 113 this.dropDown.Show(this, 0, base.Height);
  114. 114 }
  115. 115
  116. 116 protected virtual void HideDropDown()
  117. 117 {
  118. 118 this.dropDown.Hide();
  119. 119 this.dropDownOpen = false;
  120. 120 }
  121. 121
  122. 122 protected virtual void ToggleDropDown()
  123. 123 {
  124. 124 if (!this.dropDownOpen)
  125. 125 {
  126. 126 this.ShowDropDown();
  127. 127 }
  128. 128 else
  129. 129 {
  130. 130 this.HideDropDown();
  131. 131 }
  132. 132 }
  133. 133
  134. 134 protected override void WndProc(ref Message m)
  135. 135 {
  136. 136 if ((WM_LBUTTONDOWN == m.Msg) || (WM_LBUTTONDBLCLK == m.Msg))
  137. 137 {
  138. 138 if (!this.Focused)
  139. 139 {
  140. 140 this.Focus();
  141. 141 }
  142. 142 this.ToggleDropDown();
  143. 143 }
  144. 144 else
  145. 145 {
  146. 146 base.WndProc(ref m);
  147. 147 }
  148. 148 }
  149. 149
  150. 150 protected override void Dispose(bool disposing)
  151. 151 {
  152. 152 if (disposing)
  153. 153 {
  154. 154 if (this.dropDown != null)
  155. 155 {
  156. 156 this.dropDown.Dispose();
  157. 157 this.dropDown = null;
  158. 158 }
  159. 159 }
  160. 160 base.Dispose(disposing);
  161. 161 }
  162. 162
  163. 163 protected virtual void WhenTreeNodeChanged(TreeNode newValue)
  164. 164 {
  165. 165 if ((null != this.selectedNode) || (null != newValue))
  166. 166 {
  167. 167 bool changed;
  168. 168 if ((null != this.selectedNode) && (null != newValue))
  169. 169 {
  170. 170 changed = (this.selectedNode.GetHashCode() != newValue.GetHashCode());
  171. 171 }
  172. 172 else
  173. 173 {
  174. 174 changed = true;
  175. 175 }
  176. 176
  177. 177 if (changed && (null != this.TreeNodeChanged))
  178. 178 {
  179. 179 try
  180. 180 {
  181. 181 this.TreeNodeChanged.Invoke(this, new TreeNodeChangedEventArgs(this.selectedNode, newValue));
  182. 182 }
  183. 183 catch (Exception)
  184. 184 {
  185. 185 // do nothing
  186. 186 }
  187. 187 }
  188. 188
  189. 189 this.selectedNode = newValue;
  190. 190 }
  191. 191 }
  192. 192
  193. 193 protected virtual void OnDropDownClosed(object sender, ToolStripDropDownClosedEventArgs e)
  194. 194 {
  195. 195 if (null == this.toBeSelected)
  196. 196 {
  197. 197 var selectedNode = this.treeView.SelectedNode;
  198. 198 var selectedData = this.GetTreeNodeData(selectedNode);
  199. 199 this.UpdateComboBox(selectedData);
  200. 200 this.WhenTreeNodeChanged(selectedNode);
  201. 201 }
  202. 202 }
  203. 203
  204. 204 protected virtual void UpdateComboBox(T data)
  205. 205 {
  206. 206 base.DisplayMember = this.DisplayMember; // update DisplayMember
  207. 207 if (null != data)
  208. 208 {
  209. 209 this.DataSource = new List<T>() { data };
  210. 210 this.SelectedIndex = 0;
  211. 211 }
  212. 212 else
  213. 213 {
  214. 214 this.DataSource = null;
  215. 215 }
  216. 216 }
  217. 217
  218. 218 protected virtual void WhenAfterExpand(object sender, TreeViewEventArgs e)
  219. 219 {
  220. 220 if (null != this.toBeSelected)
  221. 221 {
  222. 222 if (this.SelectChildNode(e.Node.Nodes, this.toBeSelected))
  223. 223 {
  224. 224 this.toBeSelected = null;
  225. 225 }
  226. 226 }
  227. 227 }
  228. 228
  229. 229 protected virtual void WhenComboboxSizeChanged(object sender, EventArgs e)
  230. 230 {
  231. 231 this.DropDownWidth = base.Width;
  232. 232 }
  233. 233
  234. 234 public virtual bool SelectChildNode(TreeNodeCollection nodes, T data)
  235. 235 {
  236. 236 var node = this.FindChildNode(nodes, data);
  237. 237 if (null != node)
  238. 238 {
  239. 239 this.DoSelectTreeNode(node);
  240. 240 return true;
  241. 241 }
  242. 242 else
  243. 243 {
  244. 244 return false;
  245. 245 }
  246. 246 }
  247. 247
  248. 248 protected abstract bool Identical(T x, T y);
  249. 249
  250. 250 protected virtual void DoSelectTreeNode(TreeNode node)
  251. 251 {
  252. 252 this.SelectedNode = node;
  253. 253 this.ExpandTreeNode(node.Parent);
  254. 254 }
  255. 255
  256. 256 public virtual TreeNode FindChildNode(TreeNodeCollection nodes, T data)
  257. 257 {
  258. 258 foreach (TreeNode node in nodes)
  259. 259 {
  260. 260 var nodeData = this.GetTreeNodeData(node);
  261. 261 if (this.Identical(nodeData, data))
  262. 262 {
  263. 263 return node;
  264. 264 }
  265. 265 }
  266. 266
  267. 267 return null;
  268. 268 }
  269. 269
  270. 270 public virtual void ExpandTreeNode(TreeNode node)
  271. 271 {
  272. 272 if (null != node)
  273. 273 {
  274. 274 node.Expand();
  275. 275 this.ExpandTreeNode(node.Parent);
  276. 276 }
  277. 277 }
  278. 278
  279. 279 public abstract T GetTreeNodeData(TreeNode node);
  280. 280 }
  281. 281 }

完整项目下载

原文链接:http://www.cnblogs.com/yitouniu/p/11589266.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号