ScrollbarComponent.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Drawing;
  5. using System.Linq;
  6. using System.Text;
  7. using System.Windows.Forms;
  8. namespace HZH_Controls.Controls
  9. {
  10. [ProvideProperty("UserCustomScrollbar", typeof(Control))]
  11. public class ScrollbarComponent : Component, IExtenderProvider
  12. {
  13. public ScrollbarComponent()
  14. {
  15. }
  16. public ScrollbarComponent(IContainer container)
  17. {
  18. container.Add(this);
  19. }
  20. Dictionary<Control, bool> m_controlCache = new Dictionary<Control, bool>();
  21. public bool CanExtend(object extendee)
  22. {
  23. if (extendee is ScrollableControl)
  24. {
  25. ScrollableControl control = (ScrollableControl)extendee;
  26. if (control.AutoScroll == true)
  27. {
  28. return true;
  29. }
  30. }
  31. else if (extendee is TreeView)
  32. {
  33. TreeView control = (TreeView)extendee;
  34. if (control.Scrollable)
  35. {
  36. return true;
  37. }
  38. }
  39. else if (extendee is TextBox)
  40. {
  41. TextBox control = (TextBox)extendee;
  42. if (control.Multiline && control.ScrollBars != ScrollBars.None)
  43. {
  44. return true;
  45. }
  46. }
  47. return false;
  48. }
  49. [Browsable(true), Category("自定义属性"), Description("是否使用自定义滚动条"), DisplayName("UserCustomScrollbar"), Localizable(true)]
  50. public bool GetUserCustomScrollbar(Control control)
  51. {
  52. if (m_controlCache.ContainsKey(control))
  53. return m_controlCache[control];
  54. return true;
  55. }
  56. public void SetUserCustomScrollbar(Control control, bool blnUserCustomScrollbar)
  57. {
  58. m_controlCache[control] = blnUserCustomScrollbar;
  59. if (!blnUserCustomScrollbar)
  60. return;
  61. control.VisibleChanged += control_VisibleChanged;
  62. control.SizeChanged += control_SizeChanged;
  63. control.LocationChanged += control_LocationChanged;
  64. control.Disposed += control_Disposed;
  65. if (control is TreeView)
  66. {
  67. TreeView tv = (TreeView)control;
  68. tv.MouseWheel += tv_MouseWheel;
  69. tv.AfterSelect += tv_AfterSelect;
  70. tv.AfterExpand += tv_AfterExpand;
  71. tv.AfterCollapse += tv_AfterCollapse;
  72. }
  73. else if (control is TextBox)
  74. {
  75. TextBox txt = (TextBox)control;
  76. txt.MouseWheel += txt_MouseWheel;
  77. txt.TextChanged += txt_TextChanged;
  78. txt.KeyDown += txt_KeyDown;
  79. }
  80. control_SizeChanged(control, null);
  81. }
  82. void control_Disposed(object sender, EventArgs e)
  83. {
  84. Control control = (Control)sender;
  85. if (m_lstVCache.ContainsKey(control) && m_lstVCache[control].Parent != null)
  86. {
  87. m_lstVCache[control].Parent.Controls.Remove(m_lstVCache[control]);
  88. m_lstVCache.Remove(control);
  89. }
  90. }
  91. void control_LocationChanged(object sender, EventArgs e)
  92. {
  93. ResetScrollLocation(sender);
  94. }
  95. void control_SizeChanged(object sender, EventArgs e)
  96. {
  97. if (ControlHelper.IsDesignMode())
  98. {
  99. return;
  100. }
  101. else
  102. {
  103. var control = sender as Control;
  104. bool blnHasVScrollbar = control.IsHandleCreated && (ControlHelper.GetWindowLong(control.Handle, STYLE) & VSCROLL) != 0;
  105. bool blnHasHScrollbar = control.IsHandleCreated && (ControlHelper.GetWindowLong(control.Handle, STYLE) & HSCROLL) != 0;
  106. if (blnHasVScrollbar)
  107. {
  108. if (!m_lstVCache.ContainsKey(control))
  109. {
  110. if (control.Parent != null)
  111. {
  112. UCVScrollbar barV = new UCVScrollbar();
  113. barV.Width = SystemInformation.VerticalScrollBarWidth;
  114. barV.Scroll += barV_Scroll;
  115. m_lstVCache[control] = barV;
  116. if (blnHasHScrollbar)
  117. {
  118. barV.Height = control.Height - barV.Width - 2;
  119. }
  120. else
  121. {
  122. barV.Height = control.Height - 2;
  123. }
  124. SetVMaxNum(control);
  125. barV.Location = new System.Drawing.Point(control.Right - barV.Width - 1, control.Top + 1);
  126. control.Parent.Controls.Add(barV);
  127. int intControlIndex = control.Parent.Controls.GetChildIndex(control);
  128. control.Parent.Controls.SetChildIndex(barV, intControlIndex);
  129. }
  130. }
  131. else
  132. {
  133. SetVMaxNum(control);
  134. }
  135. }
  136. else
  137. {
  138. if (m_lstVCache.ContainsKey(control) && m_lstVCache[control].Parent != null)
  139. {
  140. m_lstVCache[control].Parent.Controls.Remove(m_lstVCache[control]);
  141. m_lstVCache.Remove(control);
  142. }
  143. }
  144. if (blnHasHScrollbar)
  145. {
  146. if (!m_lstHCache.ContainsKey(control))
  147. {
  148. if (control.Parent != null)
  149. {
  150. UCHScrollbar barH = new UCHScrollbar();
  151. barH.Height = SystemInformation.HorizontalScrollBarHeight;
  152. barH.Scroll += barH_Scroll;
  153. m_lstHCache[control] = barH;
  154. if (blnHasHScrollbar)
  155. {
  156. barH.Width = control.Width - barH.Height - 2;
  157. }
  158. else
  159. {
  160. barH.Width = control.Width - 2;
  161. }
  162. SetHMaxNum(control);
  163. barH.Location = new System.Drawing.Point(control.Left + 1, control.Bottom - barH.Height - 1);
  164. control.Parent.Controls.Add(barH);
  165. int intControlIndex = control.Parent.Controls.GetChildIndex(control);
  166. control.Parent.Controls.SetChildIndex(barH, intControlIndex);
  167. }
  168. }
  169. else
  170. {
  171. SetHMaxNum(control);
  172. }
  173. }
  174. else
  175. {
  176. if (m_lstHCache.ContainsKey(control))
  177. {
  178. if (m_lstHCache[control].Visible && m_lstHCache[control].Parent != null)
  179. {
  180. m_lstHCache[control].Parent.Controls.Remove(m_lstHCache[control]);
  181. }
  182. }
  183. }
  184. }
  185. ResetScrollLocation(sender);
  186. }
  187. private void SetVMaxNum(Control control)
  188. {
  189. if (!m_lstVCache.ContainsKey(control))
  190. return;
  191. var into = ControlHelper.GetVScrollBarInfo(control.Handle);
  192. var intoH = ControlHelper.GetHScrollBarInfo(control.Handle);
  193. UCVScrollbar barV = m_lstVCache[control];
  194. if (control is ScrollableControl)
  195. {
  196. barV.Maximum = (control as ScrollableControl).VerticalScroll.Maximum;
  197. barV.Value = (control as ScrollableControl).VerticalScroll.Value;
  198. }
  199. else if (control is TreeView)
  200. {
  201. barV.Maximum = GetTreeNodeMaxY(control as TreeView);
  202. barV.Value = (control as TreeView).AutoScrollOffset.Y;
  203. }
  204. else if (control is TextBox)
  205. {
  206. TextBox txt = (TextBox)control;
  207. int intTxtMaxHeight = 0;
  208. int intTextHeight = 0;
  209. using (var g = txt.CreateGraphics())
  210. {
  211. intTxtMaxHeight = (int)g.MeasureString(txt.Text, txt.Font).Height;
  212. intTextHeight = (int)g.MeasureString(txt.Text.Substring(0, txt.SelectionStart), txt.Font).Height;
  213. }
  214. barV.Maximum = intTxtMaxHeight;
  215. barV.Value = (control as TextBox).AutoScrollOffset.Y;
  216. }
  217. }
  218. private void SetHMaxNum(Control control)
  219. {
  220. if (!m_lstHCache.ContainsKey(control))
  221. return;
  222. UCHScrollbar barH = m_lstHCache[control];
  223. if (control is ScrollableControl)
  224. {
  225. barH.Maximum = (control as ScrollableControl).HorizontalScroll.Maximum;
  226. barH.Value = (control as ScrollableControl).HorizontalScroll.Value;
  227. }
  228. else if (control is TreeView)
  229. {
  230. barH.Maximum = GetTreeNodeMaxX(control as TreeView);
  231. barH.Value = (control as TreeView).AutoScrollOffset.X;
  232. }
  233. else if (control is TextBox)
  234. {
  235. TextBox txt = (TextBox)control;
  236. int intTxtMaxWidth = 0;
  237. int intTextWidth = 0;
  238. using (var g = txt.CreateGraphics())
  239. {
  240. intTxtMaxWidth = (int)g.MeasureString(txt.Text, txt.Font).Width;
  241. intTextWidth = (int)g.MeasureString(txt.Text.Substring(0, txt.SelectionStart), txt.Font).Width;
  242. }
  243. barH.Maximum = intTxtMaxWidth;
  244. barH.Value = (control as TextBox).AutoScrollOffset.Y;
  245. }
  246. }
  247. /// <summary>
  248. /// Resets the v scroll location.
  249. /// </summary>
  250. /// <param name="sender">The sender.</param>
  251. private void ResetScrollLocation(object sender)
  252. {
  253. Control control = (Control)sender;
  254. bool blnHasVScrollbar = control.IsHandleCreated && (ControlHelper.GetWindowLong(control.Handle, STYLE) & VSCROLL) != 0;
  255. bool blnHasHScrollbar = control.IsHandleCreated && (ControlHelper.GetWindowLong(control.Handle, STYLE) & HSCROLL) != 0;
  256. if (control.Visible)
  257. {
  258. if (m_lstVCache.ContainsKey(control))
  259. {
  260. m_lstVCache[control].Location = new System.Drawing.Point(control.Right - m_lstVCache[control].Width - 1, control.Top + 1);
  261. if (blnHasHScrollbar)
  262. {
  263. m_lstVCache[control].Height = control.Height - m_lstVCache[control].Width - 2;
  264. }
  265. else
  266. {
  267. m_lstVCache[control].Height = control.Height - 2;
  268. }
  269. }
  270. if (m_lstHCache.ContainsKey(control))
  271. {
  272. m_lstHCache[control].Location = new System.Drawing.Point(control.Left + 1, control.Bottom - m_lstHCache[control].Height - 1);
  273. if (blnHasHScrollbar)
  274. {
  275. m_lstHCache[control].Width = control.Width - m_lstHCache[control].Height - 2;
  276. }
  277. else
  278. {
  279. m_lstHCache[control].Width = control.Width - 2;
  280. }
  281. }
  282. }
  283. }
  284. /// <summary>
  285. /// Handles the VisibleChanged event of the control control.
  286. /// </summary>
  287. /// <param name="sender">The source of the event.</param>
  288. /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
  289. void control_VisibleChanged(object sender, EventArgs e)
  290. {
  291. Control control = (Control)sender;
  292. if (!control.Visible)
  293. {
  294. if (m_lstVCache.ContainsKey(control) && m_lstVCache[control].Parent != null)
  295. {
  296. m_lstVCache[control].Parent.Controls.Remove(m_lstVCache[control]);
  297. m_lstVCache.Remove(control);
  298. }
  299. if (m_lstHCache.ContainsKey(control) && m_lstHCache[control].Parent != null)
  300. {
  301. m_lstHCache[control].Parent.Controls.Remove(m_lstHCache[control]);
  302. m_lstHCache.Remove(control);
  303. }
  304. }
  305. }
  306. private const int HSCROLL = 0x100000;
  307. private const int VSCROLL = 0x200000;
  308. private const int STYLE = -16;
  309. private Dictionary<Control, UCVScrollbar> m_lstVCache = new Dictionary<Control, UCVScrollbar>();
  310. private Dictionary<Control, UCHScrollbar> m_lstHCache = new Dictionary<Control, UCHScrollbar>();
  311. void barV_Scroll(object sender, EventArgs e)
  312. {
  313. UCVScrollbar bar = (UCVScrollbar)sender;
  314. if (m_lstVCache.ContainsValue(bar))
  315. {
  316. Control c = m_lstVCache.FirstOrDefault(p => p.Value == bar).Key;
  317. if (c is ScrollableControl)
  318. {
  319. (c as ScrollableControl).AutoScrollPosition = new Point((c as ScrollableControl).AutoScrollPosition.X, bar.Value);
  320. }
  321. else if (c is TreeView)
  322. {
  323. TreeView tv = (c as TreeView);
  324. SetTreeViewVScrollLocation(tv, tv.Nodes, bar.Value);
  325. }
  326. else if (c is TextBox)
  327. {
  328. TextBox txt = (c as TextBox);
  329. SetTextBoxVScrollLocation(txt, bar.Value);
  330. }
  331. }
  332. }
  333. void barH_Scroll(object sender, EventArgs e)
  334. {
  335. UCHScrollbar bar = (UCHScrollbar)sender;
  336. if (m_lstHCache.ContainsValue(bar))
  337. {
  338. Control c = m_lstHCache.FirstOrDefault(p => p.Value == bar).Key;
  339. if (c is ScrollableControl)
  340. {
  341. (c as ScrollableControl).AutoScrollPosition = new Point(bar.Value, (c as ScrollableControl).AutoScrollPosition.Y);
  342. }
  343. else if (c is TreeView)
  344. {
  345. //TreeView tv = (c as TreeView);
  346. //SetTreeViewVScrollLocation(tv, tv.Nodes, bar.Value);
  347. }
  348. else if (c is TextBox)
  349. {
  350. //TextBox txt = (c as TextBox);
  351. //SetTextBoxVScrollLocation(txt, bar.Value);
  352. }
  353. }
  354. }
  355. #region Treeview处理 English:Treeview\u5904\u7406
  356. void tv_AfterCollapse(object sender, TreeViewEventArgs e)
  357. {
  358. control_SizeChanged(sender as Control, null);
  359. }
  360. void tv_AfterExpand(object sender, TreeViewEventArgs e)
  361. {
  362. control_SizeChanged(sender as Control, null);
  363. }
  364. /// <summary>
  365. /// Gets the tree node 最大高度
  366. /// </summary>
  367. /// <param name="tv">The tv.</param>
  368. /// <returns>System.Int32.</returns>
  369. private int GetTreeNodeMaxY(TreeView tv)
  370. {
  371. TreeNode tnLast = tv.Nodes[tv.Nodes.Count - 1];
  372. begin:
  373. if (tnLast.IsExpanded && tnLast.Nodes.Count > 0)
  374. {
  375. tnLast = tnLast.LastNode;
  376. goto begin;
  377. }
  378. return tnLast.Bounds.Bottom;
  379. }
  380. private int GetTreeNodeMaxX(TreeView tv)
  381. {
  382. return tv.Nodes.Count != 0 ? tv.Nodes[0].Bounds.Right : 0;
  383. }
  384. void tv_AfterSelect(object sender, TreeViewEventArgs e)
  385. {
  386. TreeView tv = (TreeView)sender;
  387. if (m_lstVCache.ContainsKey(tv))
  388. {
  389. m_lstVCache[tv].Value = tv.Nodes.Count > 0 ? Math.Abs(tv.Nodes[0].Bounds.Top) : 0;
  390. }
  391. }
  392. void tv_MouseWheel(object sender, MouseEventArgs e)
  393. {
  394. TreeView tv = (TreeView)sender;
  395. if (m_lstVCache.ContainsKey(tv))
  396. {
  397. m_lstVCache[tv].Value = tv.Nodes.Count > 0 ? Math.Abs(tv.Nodes[0].Bounds.Top) : 0;
  398. }
  399. }
  400. /// <summary>
  401. /// Sets the TreeView scroll location.
  402. /// </summary>
  403. /// <param name="tv">The tv.</param>
  404. /// <param name="tns">The TNS.</param>
  405. /// <param name="intY">The int y.</param>
  406. /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
  407. private bool SetTreeViewVScrollLocation(TreeView tv, TreeNodeCollection tns, int intY)
  408. {
  409. for (int i = 0; i < tns.Count; i++)
  410. {
  411. if (intY >= tns[i].Bounds.Top - tv.Nodes[0].Bounds.Top - 3 && intY <= tns[i].Bounds.Bottom - tv.Nodes[0].Bounds.Top + 3)
  412. {
  413. tns[i].EnsureVisible();
  414. return true;
  415. }
  416. else if (tns[i].IsExpanded && tns[i].Nodes.Count > 0)
  417. {
  418. bool bln = SetTreeViewVScrollLocation(tv, tns[i].Nodes, intY);
  419. if (bln)
  420. return true;
  421. }
  422. }
  423. return false;
  424. }
  425. #endregion
  426. #region TextBox处理 English:TextBox Processing
  427. void txt_TextChanged(object sender, EventArgs e)
  428. {
  429. TextBox txt = sender as TextBox;
  430. control_SizeChanged(txt, null);
  431. SetVMaxNum(txt);
  432. if (m_lstVCache.ContainsKey(txt))
  433. {
  434. using (var g = txt.CreateGraphics())
  435. {
  436. var size = g.MeasureString(txt.Text.Substring(0, txt.SelectionStart), txt.Font);
  437. m_lstVCache[txt].Value = (int)size.Height;
  438. }
  439. }
  440. }
  441. private void SetTextBoxVScrollLocation(TextBox txt, int intY)
  442. {
  443. using (var g = txt.CreateGraphics())
  444. {
  445. for (int i = 0; i < txt.Lines.Length; i++)
  446. {
  447. string str = string.Join("\n", txt.Lines.Take(i + 1));
  448. var size = g.MeasureString(str, txt.Font);
  449. if (size.Height >= intY)
  450. {
  451. txt.SelectionStart = str.Length;
  452. txt.ScrollToCaret();
  453. return;
  454. }
  455. }
  456. }
  457. }
  458. void txt_KeyDown(object sender, KeyEventArgs e)
  459. {
  460. if (e.KeyCode == Keys.Up || e.KeyCode == Keys.Down)
  461. {
  462. TextBox txt = (TextBox)sender;
  463. if (m_lstVCache.ContainsKey(txt))
  464. {
  465. using (var g = txt.CreateGraphics())
  466. {
  467. var size = g.MeasureString(txt.Text.Substring(0, txt.SelectionStart), txt.Font);
  468. m_lstVCache[txt].Value = (int)size.Height;
  469. }
  470. }
  471. }
  472. }
  473. void txt_MouseWheel(object sender, MouseEventArgs e)
  474. {
  475. TextBox txt = (TextBox)sender;
  476. if (m_lstVCache.ContainsKey(txt))
  477. {
  478. using (var g = txt.CreateGraphics())
  479. {
  480. StringBuilder str = new StringBuilder();
  481. for (int i = 0; i < System.Windows.Forms.SystemInformation.MouseWheelScrollLines; i++)
  482. {
  483. str.AppendLine("A");
  484. }
  485. var height = (int)g.MeasureString(str.ToString(), txt.Font).Height;
  486. if (e.Delta < 0)
  487. {
  488. if (height + m_lstVCache[txt].Value > m_lstVCache[txt].Maximum)
  489. m_lstVCache[txt].Value = m_lstVCache[txt].Maximum;
  490. else
  491. m_lstVCache[txt].Value += height;
  492. }
  493. else
  494. {
  495. if (m_lstVCache[txt].Value - height < 0)
  496. m_lstVCache[txt].Value = 0;
  497. else
  498. m_lstVCache[txt].Value -= height;
  499. }
  500. }
  501. }
  502. }
  503. #endregion
  504. }
  505. }