参考链接:https://www.cnblogs.com/xe2011/p/3817402.html

    尽可能接近WINDOWS 8的资源管理器效果(这里只模仿它的效果,处理文件功能不包括在内)

    1. TREEVIEW可以增加空白并且空白处不能单击
    2. 重绘三角箭头
    3. 重绘选中时的边框和填充色
    4. 重绘失去焦点时选中时的边框和填充色
    5. 重绘光标所在处的节点背景 MOUSE Hover
    6. 闪烁的问题处理 当TREEVIEW大小改变时闪烁很严重
    7. 做到自定义控件
    8. 图片背景
    9. 光标的在不同位置的相关改变
    10. WINDOWS 8的资源管理器是不显示水平滚动条


      相关参考

      重画节点的+-号 http://stackoverflow.com/questions/20125131/treeview-change-plus-minus-icon
      画节点上的ImageList的图标 http://zhuad627.blog.163.com/blog/static/94780512011618103157479/
      画节点文字后面的 TAG http://www.cnblogs.com/scottckt/archive/2007/12/18/1005084.html

      http://www.cnblogs.com/xm_cpppp/p/3622434.html
      0 Explore TreeView - 图1

      选中的节点颜色
      0 Explore TreeView - 图2
      边框颜色 102,167,232
      填充颜色 209,232,255

      TREEVIEW失去焦点
      0 Explore TreeView - 图3
      边框颜色 222,222,222
      填充颜色 247,247,247


      光标所在的节点的
      0 Explore TreeView - 图4
      边框颜色 112,192,231
      填充颜色 229,243,251

      0 Explore TreeView - 图5

      光标的在不同位置的相关改变
      0 Explore TreeView - 图6

    12 TreeViewEx.cs 源码

    文件下载:http://files.cnblogs.com/files/xe2011/CSharpExploreTreeView2016-11-23_165057.zip
    编译环境是vs2015 文件已经解决了控件闪烁问题
    完整的文件的源码:http://www.cnblogs.com/xe2011/p/3859801.html

    1. using System.Drawing;
    2. using System.Runtime.InteropServices;
    3. namespace System.Windows.Forms
    4. {
    5. public class API
    6. {
    7. private const int WS_HSCROLL = 0x100000;
    8. private const int WS_VSCROLL = 0x200000;
    9. private const int GWL_STYLE = (-16);
    10. [DllImport("User32.dll")]
    11. public static extern IntPtr LoadCursor(IntPtr hInstance, CursorType cursor);
    12. [DllImport("user32.dll")]
    13. public static extern int GetWindowLong(IntPtr hwnd, int nIndex);
    14. [DllImport("user32.dll")]
    15. public static extern bool ShowScrollBar(IntPtr hWnd, int wBar, bool bShow);
    16. public const int WM_PRINTCLIENT = 0x0318;
    17. public const int PRF_CLIENT = 0x00000004;
    18. [DllImport("user32.dll")]
    19. public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
    20. /// <summary>
    21. /// 显示系统光标小手
    22. /// 像Win7非经典主题的小手光标
    23. /// </summary>
    24. public static Cursor Hand
    25. {
    26. get
    27. {
    28. IntPtr h = LoadCursor(IntPtr.Zero, CursorType.IDC_HAND);
    29. return new Cursor(h);
    30. }
    31. }
    32. public static bool IsWinXP
    33. {
    34. get
    35. {
    36. OperatingSystem OS = Environment.OSVersion;
    37. return (OS.Platform == PlatformID.Win32NT) &&
    38. ((OS.Version.Major > 5) || ((OS.Version.Major == 5) && (OS.Version.Minor == 1)));
    39. }
    40. }
    41. public static bool IsWinVista
    42. {
    43. get
    44. {
    45. OperatingSystem OS = Environment.OSVersion;
    46. return (OS.Platform == PlatformID.Win32NT) && (OS.Version.Major >= 6);
    47. }
    48. }
    49. /// <summary>
    50. /// 判断是否出现垂直滚动条
    51. /// </summary>
    52. /// <param name="ctrl">待测控件</param>
    53. /// <returns>出现垂直滚动条返回true,否则为false</returns>
    54. public static bool IsVerticalScrollBarVisible(Control ctrl)
    55. {
    56. if (!ctrl.IsHandleCreated)
    57. return false;
    58. return (GetWindowLong(ctrl.Handle, GWL_STYLE) & WS_VSCROLL) != 0;
    59. }
    60. /// <summary>
    61. /// 判断是否出现水平滚动条
    62. /// </summary>
    63. /// <param name="ctrl">待测控件</param>
    64. /// <returns>出现水平滚动条返回true,否则为false</returns>
    65. public static bool IsHorizontalScrollBarVisible(Control ctrl)
    66. {
    67. if (!ctrl.IsHandleCreated)
    68. return false;
    69. return (GetWindowLong(ctrl.Handle, GWL_STYLE) & WS_HSCROLL) != 0;
    70. }
    71. }
    72. public enum CursorType : uint
    73. {
    74. IDC_ARROW = 32512U,
    75. IDC_IBEAM = 32513U,
    76. IDC_WAIT = 32514U,
    77. IDC_CROSS = 32515U,
    78. IDC_UPARROW = 32516U,
    79. IDC_SIZE = 32640U,
    80. IDC_ICON = 32641U,
    81. IDC_SIZENWSE = 32642U,
    82. IDC_SIZENESW = 32643U,
    83. IDC_SIZEWE = 32644U,
    84. IDC_SIZENS = 32645U,
    85. IDC_SIZEALL = 32646U,
    86. IDC_NO = 32648U,
    87. //小手
    88. IDC_HAND = 32649U,
    89. IDC_APPSTARTING = 32650U,
    90. IDC_HELP = 32651U
    91. }
    92. public class TreeViewEx : TreeView
    93. {
    94. #region 双缓存重绘
    95. private const int WM_VSCROLL = 0x0115;
    96. private const int WM_HSCROLL = 0x0114;
    97. //private const int WM_MOUSEWHEEL = 0x020A;
    98. private const int TV_FIRST = 0x1100;
    99. private const int TVM_SETBKCOLOR = TV_FIRST + 29;
    100. private const int TVM_SETEXTENDEDSTYLE = TV_FIRST + 44;
    101. private const int TVS_EX_DOUBLEBUFFER = 0x0004;
    102. private void UpdateExtendedStyles()
    103. {
    104. int Style = 0;
    105. if (DoubleBuffered)
    106. Style |= TVS_EX_DOUBLEBUFFER;
    107. if (Style != 0)
    108. API.SendMessage(Handle, TVM_SETEXTENDEDSTYLE, (IntPtr)TVS_EX_DOUBLEBUFFER, (IntPtr)Style);
    109. }
    110. protected override void OnHandleCreated(EventArgs e)
    111. {
    112. base.OnHandleCreated(e);
    113. UpdateExtendedStyles();
    114. if (!API.IsWinXP)
    115. API.SendMessage(Handle, TVM_SETBKCOLOR, IntPtr.Zero, (IntPtr)ColorTranslator.ToWin32(BackColor));
    116. }
    117. protected override void OnPaint(PaintEventArgs e)
    118. {
    119. if (GetStyle(ControlStyles.UserPaint))
    120. {
    121. Message m = new Message();
    122. m.HWnd = Handle;
    123. m.Msg = API.WM_PRINTCLIENT;
    124. m.WParam = e.Graphics.GetHdc();
    125. m.LParam = (IntPtr)API.PRF_CLIENT;
    126. DefWndProc(ref m);
    127. e.Graphics.ReleaseHdc(m.WParam);
    128. }
    129. base.OnPaint(e);
    130. }
    131. #endregion
    132. public TreeViewEx()
    133. {
    134. treeView1 = this;
    135. treeView1.HotTracking = true;
    136. treeView1.HideSelection = false;
    137. treeView1.SelectedImageIndex = treeView1.ImageIndex;
    138. this.treeView1.BackColor = System.Drawing.Color.White;
    139. this.treeView1.BorderStyle = System.Windows.Forms.BorderStyle.None;
    140. this.treeView1.Font = new System.Drawing.Font("微软雅黑", 9.7F);
    141. this.treeView1.FullRowSelect = true;
    142. treeView1.DrawMode = TreeViewDrawMode.OwnerDrawAll;
    143. //treeView1.Nodes[1].Expand();
    144. //treeView1.Nodes[5].Expand();
    145. //treeView1.SelectedNode = treeView1.Nodes[1];
    146. this.treeView1.DrawNode += new System.Windows.Forms.DrawTreeNodeEventHandler(this.treeView1_DrawNode);
    147. this.treeView1.BeforeSelect += new System.Windows.Forms.TreeViewCancelEventHandler(this.treeView1_BeforeSelect);
    148. this.treeView1.KeyDown += new System.Windows.Forms.KeyEventHandler(this.treeView1_KeyDown);
    149. }
    150. #region DrawNode
    151. public ImageList arrowImageList
    152. {
    153. get
    154. {
    155. return arrowImageList1;
    156. }
    157. set
    158. {
    159. arrowImageList1 = value;
    160. }
    161. }
    162. /*1节点被选中 ,TreeView有焦点*/
    163. private SolidBrush brush1 = new SolidBrush(Color.FromArgb(209, 232, 255));//填充颜色
    164. private Pen pen1 = new Pen(Color.FromArgb(102, 167, 232), 1);//边框颜色
    165. /*2节点被选中 ,TreeView没有焦点*/
    166. private SolidBrush brush2 = new SolidBrush(Color.FromArgb(247, 247, 247));
    167. private Pen pen2 = new Pen(Color.FromArgb(222, 222, 222), 1);
    168. /*3 MouseMove的时候 画光标所在的节点的背景*/
    169. private SolidBrush brush3 = new SolidBrush(Color.FromArgb(229, 243, 251));
    170. private Pen pen3 = new Pen(Color.FromArgb(112, 192, 231), 1);
    171. private void treeView1_DrawNode(object sender, DrawTreeNodeEventArgs e)
    172. {
    173. #region 1 选中的节点背景=========================================
    174. Rectangle nodeRect = new Rectangle(1,
    175. e.Bounds.Top,
    176. e.Bounds.Width - 3,
    177. e.Bounds.Height - 1);
    178. if (e.Node.IsSelected)
    179. {
    180. //TreeView有焦点的时候 画选中的节点
    181. if (treeView1.Focused)
    182. {
    183. e.Graphics.FillRectangle(brush1, nodeRect);
    184. e.Graphics.DrawRectangle(pen1, nodeRect);
    185. /*测试 画聚焦的边框*/
    186. //ControlPaint.DrawFocusRectangle(e.Graphics, e.Bounds, Color.Black, SystemColors.Highlight);
    187. }
    188. /*TreeView失去焦点的时候 */
    189. else
    190. {
    191. e.Graphics.FillRectangle(brush2, nodeRect);
    192. e.Graphics.DrawRectangle(pen2, nodeRect);
    193. }
    194. }
    195. else if ((e.State & TreeNodeStates.Hot) != 0 && e.Node.Text != "")//|| currentMouseMoveNode == e.Node)
    196. {
    197. e.Graphics.FillRectangle(brush3, nodeRect);
    198. e.Graphics.DrawRectangle(pen3, nodeRect);
    199. }
    200. else
    201. {
    202. e.Graphics.FillRectangle(Brushes.White, e.Bounds);
    203. }
    204. #endregion
    205. #region 2 +-号绘制=========================================
    206. Rectangle plusRect = new Rectangle(e.Node.Bounds.Left - 32, nodeRect.Top + 7, 9, 9); // +-号的大小 是9 * 9
    207. if (e.Node.IsExpanded)
    208. e.Graphics.DrawImage(arrowImageList.Images[1], plusRect);
    209. else if (e.Node.IsExpanded == false && e.Node.Nodes.Count > 0)
    210. e.Graphics.DrawImage(arrowImageList.Images[0], plusRect);
    211. /*测试用 画出+-号出现的矩形*/
    212. //if (e.Node.Nodes.Count > 0)
    213. // e.Graphics.DrawRectangle(new Pen(Color.Red), plusRect);
    214. #endregion
    215. #region 3 画节点文本=========================================
    216. Rectangle nodeTextRect = new Rectangle(
    217. e.Node.Bounds.Left,
    218. e.Node.Bounds.Top + 2,
    219. e.Node.Bounds.Width + 2,
    220. e.Node.Bounds.Height
    221. );
    222. nodeTextRect.Width += 4;
    223. nodeTextRect.Height -= 4;
    224. e.Graphics.DrawString(e.Node.Text,
    225. e.Node.TreeView.Font,
    226. new SolidBrush(Color.Black),
    227. nodeTextRect);
    228. //画子节点个数 (111)
    229. if (e.Node.GetNodeCount(true) > 0)
    230. {
    231. e.Graphics.DrawString(string.Format("({0})", e.Node.GetNodeCount(true)),
    232. new Font("Arial", 8),
    233. Brushes.Gray,
    234. nodeTextRect.Right - 4,
    235. nodeTextRect.Top + 2);
    236. }
    237. ///*测试用,画文字出现的矩形*/
    238. //if (e.Node.Text != "")
    239. // e.Graphics.DrawRectangle(new Pen(Color.Blue), nodeTextRect);
    240. #endregion
    241. #region 4 画IImageList 中的图标===================================================================
    242. int currt_X = e.Node.Bounds.X;
    243. if (treeView1.ImageList != null && treeView1.ImageList.Images.Count > 0)
    244. {
    245. //图标大小16*16
    246. Rectangle imagebox = new Rectangle(
    247. e.Node.Bounds.X - 3 - 16,
    248. e.Node.Bounds.Y + 3,
    249. 16,//IMAGELIST IMAGE WIDTH
    250. 16);//HEIGHT
    251. int index = e.Node.ImageIndex;
    252. string imagekey = e.Node.ImageKey;
    253. if (imagekey != "" && treeView1.ImageList.Images.ContainsKey(imagekey))
    254. e.Graphics.DrawImage(treeView1.ImageList.Images[imagekey], imagebox);
    255. else
    256. {
    257. if (e.Node.ImageIndex < 0)
    258. index = 0;
    259. else if (index > treeView1.ImageList.Images.Count - 1)
    260. index = 0;
    261. e.Graphics.DrawImage(treeView1.ImageList.Images[index], imagebox);
    262. }
    263. currt_X -= 19;
    264. /*测试 画IMAGELIST的矩形*/
    265. //if (e.Node.ImageIndex > 0)
    266. // e.Graphics.DrawRectangle(new Pen(Color.Black, 1), imagebox);
    267. }
    268. #endregion
    269. ///*测试 画所有的边框*/
    270. //nodeRect = new Rectangle(1,
    271. // e.Bounds.Top + 1,
    272. // e.Bounds.Width - 3,
    273. // e.Bounds.Height - 2);
    274. //e.Graphics.DrawRectangle(new Pen(Color.Gray), nodeRect);
    275. }
    276. #endregion
    277. private void treeView1_BeforeSelect(object sender, TreeViewCancelEventArgs e)
    278. {
    279. if (e.Node != null)
    280. {
    281. //禁止选中空白项
    282. if (e.Node.Text == "")
    283. {
    284. //响应上下键
    285. if (ArrowKeyUp)
    286. {
    287. if (e.Node.PrevNode != null && e.Node.PrevNode.Text != "")
    288. treeView1.SelectedNode = e.Node.PrevNode;
    289. }
    290. if (ArrowKeyDown)
    291. {
    292. if (e.Node.NextNode != null && e.Node.NextNode.Text != "")
    293. treeView1.SelectedNode = e.Node.NextNode;
    294. }
    295. e.Cancel = true;
    296. }
    297. }
    298. }
    299. private void treeView1_KeyDown(object sender, KeyEventArgs e)
    300. {
    301. ArrowKeyUp = (e.KeyCode == Keys.Up);
    302. if (e.KeyCode == Keys.Down)
    303. {
    304. Text = "Down";
    305. }
    306. ArrowKeyDown = (e.KeyCode == Keys.Down);
    307. if (e.KeyCode == Keys.Up)
    308. {
    309. Text = "UP";
    310. }
    311. }
    312. private bool ArrowKeyUp = false;
    313. private bool ArrowKeyDown = false;
    314. private System.Windows.Forms.ImageList arrowImageList1;
    315. private TreeView treeView1;
    316. }
    317. }