DockPanel.FocusManager.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682
  1. /*******************************************************************************
  2. * Copyright(c) 2014 DongkeSoft All rights reserved. / Confidential
  3. * 类的信息:
  4. * 1.程序名称:DockPanel.cs
  5. * 2.功能描述:类文件
  6. * 编辑履历:
  7. * 作者 日期 版本 修改内容
  8. * 陈晓野 2014/09/01 1.00 新建
  9. *******************************************************************************/
  10. using System;
  11. using System.Collections.Generic;
  12. using System.ComponentModel;
  13. using System.Diagnostics.CodeAnalysis;
  14. using System.Runtime.InteropServices;
  15. using System.Windows.Forms;
  16. namespace Dongke.IBOSS.PRD.Basics.DockPanel
  17. {
  18. /// <summary>
  19. /// 类文件
  20. /// </summary>
  21. internal interface IContentFocusManager
  22. {
  23. void Activate(IDockContent content);
  24. void GiveUpFocus(IDockContent content);
  25. void AddToList(IDockContent content);
  26. void RemoveFromList(IDockContent content);
  27. }
  28. partial class DockPanel
  29. {
  30. private interface IFocusManager
  31. {
  32. void SuspendFocusTracking();
  33. void ResumeFocusTracking();
  34. bool IsFocusTrackingSuspended
  35. {
  36. get;
  37. }
  38. IDockContent ActiveContent
  39. {
  40. get;
  41. }
  42. DockPane ActivePane
  43. {
  44. get;
  45. }
  46. IDockContent ActiveDocument
  47. {
  48. get;
  49. }
  50. DockPane ActiveDocumentPane
  51. {
  52. get;
  53. }
  54. }
  55. private class FocusManagerImpl : Component, IContentFocusManager, IFocusManager
  56. {
  57. private class HookEventArgs : EventArgs
  58. {
  59. [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")]
  60. public int HookCode;
  61. [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")]
  62. public IntPtr wParam;
  63. public IntPtr lParam;
  64. }
  65. private class LocalWindowsHook : IDisposable
  66. {
  67. // Internal properties
  68. private IntPtr m_hHook = IntPtr.Zero;
  69. private NativeMethods.HookProc m_filterFunc = null;
  70. private Win32.HookType m_hookType;
  71. // Event delegate
  72. public delegate void HookEventHandler(object sender, HookEventArgs e);
  73. // Event: HookInvoked
  74. public event HookEventHandler HookInvoked;
  75. protected void OnHookInvoked(HookEventArgs e)
  76. {
  77. if (HookInvoked != null)
  78. HookInvoked(this, e);
  79. }
  80. public LocalWindowsHook(Win32.HookType hook)
  81. {
  82. m_hookType = hook;
  83. m_filterFunc = new NativeMethods.HookProc(this.CoreHookProc);
  84. }
  85. // Default filter function
  86. public IntPtr CoreHookProc(int code, IntPtr wParam, IntPtr lParam)
  87. {
  88. if (code < 0)
  89. return NativeMethods.CallNextHookEx(m_hHook, code, wParam, lParam);
  90. // Let clients determine what to do
  91. HookEventArgs e = new HookEventArgs();
  92. e.HookCode = code;
  93. e.wParam = wParam;
  94. e.lParam = lParam;
  95. OnHookInvoked(e);
  96. // Yield to the next hook in the chain
  97. return NativeMethods.CallNextHookEx(m_hHook, code, wParam, lParam);
  98. }
  99. // Install the hook
  100. public void Install()
  101. {
  102. if (m_hHook != IntPtr.Zero)
  103. Uninstall();
  104. int threadId = NativeMethods.GetCurrentThreadId();
  105. m_hHook = NativeMethods.SetWindowsHookEx(m_hookType, m_filterFunc, IntPtr.Zero, threadId);
  106. }
  107. // Uninstall the hook
  108. public void Uninstall()
  109. {
  110. if (m_hHook != IntPtr.Zero)
  111. {
  112. NativeMethods.UnhookWindowsHookEx(m_hHook);
  113. m_hHook = IntPtr.Zero;
  114. }
  115. }
  116. ~LocalWindowsHook()
  117. {
  118. Dispose(false);
  119. }
  120. public void Dispose()
  121. {
  122. Dispose(true);
  123. GC.SuppressFinalize(this);
  124. }
  125. protected virtual void Dispose(bool disposing)
  126. {
  127. Uninstall();
  128. }
  129. }
  130. private static LocalWindowsHook sm_localWindowsHook;
  131. private LocalWindowsHook.HookEventHandler m_hookEventHandler;
  132. // Use a static instance of the windows hook to prevent stack overflows in the windows kernel.
  133. static FocusManagerImpl()
  134. {
  135. if (Win32Helper.IsRunningOnMono)
  136. return;
  137. sm_localWindowsHook = new LocalWindowsHook(Win32.HookType.WH_CALLWNDPROCRET);
  138. sm_localWindowsHook.Install();
  139. }
  140. public FocusManagerImpl(DockPanel dockPanel)
  141. {
  142. m_dockPanel = dockPanel;
  143. if (Win32Helper.IsRunningOnMono)
  144. return;
  145. m_hookEventHandler = new LocalWindowsHook.HookEventHandler(HookEventHandler);
  146. sm_localWindowsHook.HookInvoked += m_hookEventHandler;
  147. }
  148. private DockPanel m_dockPanel;
  149. public DockPanel DockPanel
  150. {
  151. get
  152. {
  153. return m_dockPanel;
  154. }
  155. }
  156. private bool m_disposed = false;
  157. protected override void Dispose(bool disposing)
  158. {
  159. lock (this)
  160. {
  161. if (!m_disposed && disposing)
  162. {
  163. if (!Win32Helper.IsRunningOnMono)
  164. sm_localWindowsHook.HookInvoked -= m_hookEventHandler;
  165. m_disposed = true;
  166. }
  167. base.Dispose(disposing);
  168. }
  169. }
  170. private IDockContent m_contentActivating = null;
  171. private IDockContent ContentActivating
  172. {
  173. get
  174. {
  175. return m_contentActivating;
  176. }
  177. set
  178. {
  179. m_contentActivating = value;
  180. }
  181. }
  182. public void Activate(IDockContent content)
  183. {
  184. if (IsFocusTrackingSuspended)
  185. {
  186. ContentActivating = content;
  187. return;
  188. }
  189. if (content == null)
  190. return;
  191. DockContentHandler handler = content.DockHandler;
  192. if (handler.Form.IsDisposed)
  193. return; // Should not reach here, but better than throwing an exception
  194. if (ContentContains(content, handler.ActiveWindowHandle))
  195. if (!Win32Helper.IsRunningOnMono)
  196. NativeMethods.SetFocus(handler.ActiveWindowHandle);
  197. if (!handler.Form.ContainsFocus)
  198. {
  199. if (!handler.Form.SelectNextControl(handler.Form.ActiveControl, true, true, true, true))
  200. // Since DockContent Form is not selectalbe, use Win32 SetFocus instead
  201. if (!Win32Helper.IsRunningOnMono)
  202. NativeMethods.SetFocus(handler.Form.Handle);
  203. }
  204. }
  205. private List<IDockContent> m_listContent = new List<IDockContent>();
  206. private List<IDockContent> ListContent
  207. {
  208. get
  209. {
  210. return m_listContent;
  211. }
  212. }
  213. public void AddToList(IDockContent content)
  214. {
  215. if (ListContent.Contains(content) || IsInActiveList(content))
  216. return;
  217. ListContent.Add(content);
  218. }
  219. public void RemoveFromList(IDockContent content)
  220. {
  221. if (IsInActiveList(content))
  222. RemoveFromActiveList(content);
  223. if (ListContent.Contains(content))
  224. ListContent.Remove(content);
  225. }
  226. private IDockContent m_lastActiveContent = null;
  227. private IDockContent LastActiveContent
  228. {
  229. get
  230. {
  231. return m_lastActiveContent;
  232. }
  233. set
  234. {
  235. m_lastActiveContent = value;
  236. }
  237. }
  238. private bool IsInActiveList(IDockContent content)
  239. {
  240. return !(content.DockHandler.NextActive == null && LastActiveContent != content);
  241. }
  242. private void AddLastToActiveList(IDockContent content)
  243. {
  244. IDockContent last = LastActiveContent;
  245. if (last == content)
  246. return;
  247. DockContentHandler handler = content.DockHandler;
  248. if (IsInActiveList(content))
  249. RemoveFromActiveList(content);
  250. handler.PreviousActive = last;
  251. handler.NextActive = null;
  252. LastActiveContent = content;
  253. if (last != null)
  254. last.DockHandler.NextActive = LastActiveContent;
  255. }
  256. private void RemoveFromActiveList(IDockContent content)
  257. {
  258. if (LastActiveContent == content)
  259. LastActiveContent = content.DockHandler.PreviousActive;
  260. IDockContent prev = content.DockHandler.PreviousActive;
  261. IDockContent next = content.DockHandler.NextActive;
  262. if (prev != null)
  263. prev.DockHandler.NextActive = next;
  264. if (next != null)
  265. next.DockHandler.PreviousActive = prev;
  266. content.DockHandler.PreviousActive = null;
  267. content.DockHandler.NextActive = null;
  268. }
  269. public void GiveUpFocus(IDockContent content)
  270. {
  271. DockContentHandler handler = content.DockHandler;
  272. if (!handler.Form.ContainsFocus)
  273. return;
  274. if (IsFocusTrackingSuspended)
  275. DockPanel.DummyControl.Focus();
  276. if (LastActiveContent == content)
  277. {
  278. IDockContent prev = handler.PreviousActive;
  279. if (prev != null)
  280. Activate(prev);
  281. else if (ListContent.Count > 0)
  282. Activate(ListContent[ListContent.Count - 1]);
  283. }
  284. else if (LastActiveContent != null)
  285. Activate(LastActiveContent);
  286. else if (ListContent.Count > 0)
  287. Activate(ListContent[ListContent.Count - 1]);
  288. }
  289. private static bool ContentContains(IDockContent content, IntPtr hWnd)
  290. {
  291. Control control = Control.FromChildHandle(hWnd);
  292. for (Control parent = control; parent != null; parent = parent.Parent)
  293. if (parent == content.DockHandler.Form)
  294. return true;
  295. return false;
  296. }
  297. private int m_countSuspendFocusTracking = 0;
  298. public void SuspendFocusTracking()
  299. {
  300. m_countSuspendFocusTracking++;
  301. if (!Win32Helper.IsRunningOnMono)
  302. sm_localWindowsHook.HookInvoked -= m_hookEventHandler;
  303. }
  304. public void ResumeFocusTracking()
  305. {
  306. if (m_countSuspendFocusTracking > 0)
  307. m_countSuspendFocusTracking--;
  308. if (m_countSuspendFocusTracking == 0)
  309. {
  310. if (ContentActivating != null)
  311. {
  312. Activate(ContentActivating);
  313. ContentActivating = null;
  314. }
  315. if (!Win32Helper.IsRunningOnMono)
  316. sm_localWindowsHook.HookInvoked += m_hookEventHandler;
  317. if (!InRefreshActiveWindow)
  318. RefreshActiveWindow();
  319. }
  320. }
  321. public bool IsFocusTrackingSuspended
  322. {
  323. get
  324. {
  325. return m_countSuspendFocusTracking != 0;
  326. }
  327. }
  328. // Windows hook event handler
  329. private void HookEventHandler(object sender, HookEventArgs e)
  330. {
  331. Win32.Msgs msg = (Win32.Msgs)Marshal.ReadInt32(e.lParam, IntPtr.Size * 3);
  332. if (msg == Win32.Msgs.WM_KILLFOCUS)
  333. {
  334. IntPtr wParam = Marshal.ReadIntPtr(e.lParam, IntPtr.Size * 2);
  335. DockPane pane = GetPaneFromHandle(wParam);
  336. if (pane == null)
  337. RefreshActiveWindow();
  338. }
  339. else if (msg == Win32.Msgs.WM_SETFOCUS)
  340. RefreshActiveWindow();
  341. }
  342. private DockPane GetPaneFromHandle(IntPtr hWnd)
  343. {
  344. Control control = Control.FromChildHandle(hWnd);
  345. IDockContent content = null;
  346. DockPane pane = null;
  347. for (; control != null; control = control.Parent)
  348. {
  349. content = control as IDockContent;
  350. if (content != null)
  351. content.DockHandler.ActiveWindowHandle = hWnd;
  352. if (content != null && content.DockHandler.DockPanel == DockPanel)
  353. return content.DockHandler.Pane;
  354. pane = control as DockPane;
  355. if (pane != null && pane.DockPanel == DockPanel)
  356. break;
  357. }
  358. return pane;
  359. }
  360. private bool m_inRefreshActiveWindow = false;
  361. private bool InRefreshActiveWindow
  362. {
  363. get
  364. {
  365. return m_inRefreshActiveWindow;
  366. }
  367. }
  368. private void RefreshActiveWindow()
  369. {
  370. SuspendFocusTracking();
  371. m_inRefreshActiveWindow = true;
  372. DockPane oldActivePane = ActivePane;
  373. IDockContent oldActiveContent = ActiveContent;
  374. IDockContent oldActiveDocument = ActiveDocument;
  375. SetActivePane();
  376. SetActiveContent();
  377. SetActiveDocumentPane();
  378. SetActiveDocument();
  379. DockPanel.AutoHideWindow.RefreshActivePane();
  380. ResumeFocusTracking();
  381. m_inRefreshActiveWindow = false;
  382. if (oldActiveContent != ActiveContent)
  383. DockPanel.OnActiveContentChanged(EventArgs.Empty);
  384. if (oldActiveDocument != ActiveDocument)
  385. DockPanel.OnActiveDocumentChanged(EventArgs.Empty);
  386. if (oldActivePane != ActivePane)
  387. DockPanel.OnActivePaneChanged(EventArgs.Empty);
  388. }
  389. private DockPane m_activePane = null;
  390. public DockPane ActivePane
  391. {
  392. get
  393. {
  394. return m_activePane;
  395. }
  396. }
  397. private void SetActivePane()
  398. {
  399. DockPane value = Win32Helper.IsRunningOnMono ? null : GetPaneFromHandle(NativeMethods.GetFocus());
  400. if (m_activePane == value)
  401. return;
  402. if (m_activePane != null)
  403. m_activePane.SetIsActivated(false);
  404. m_activePane = value;
  405. if (m_activePane != null)
  406. m_activePane.SetIsActivated(true);
  407. }
  408. private IDockContent m_activeContent = null;
  409. public IDockContent ActiveContent
  410. {
  411. get
  412. {
  413. return m_activeContent;
  414. }
  415. }
  416. internal void SetActiveContent()
  417. {
  418. IDockContent value = ActivePane == null ? null : ActivePane.ActiveContent;
  419. if (m_activeContent == value)
  420. return;
  421. if (m_activeContent != null)
  422. m_activeContent.DockHandler.IsActivated = false;
  423. m_activeContent = value;
  424. if (m_activeContent != null)
  425. {
  426. m_activeContent.DockHandler.IsActivated = true;
  427. if (!DockHelper.IsDockStateAutoHide((m_activeContent.DockHandler.DockState)))
  428. AddLastToActiveList(m_activeContent);
  429. }
  430. }
  431. private DockPane m_activeDocumentPane = null;
  432. public DockPane ActiveDocumentPane
  433. {
  434. get
  435. {
  436. return m_activeDocumentPane;
  437. }
  438. }
  439. private void SetActiveDocumentPane()
  440. {
  441. DockPane value = null;
  442. if (ActivePane != null && ActivePane.DockState == DockState.Document)
  443. value = ActivePane;
  444. if (value == null && DockPanel.DockWindows != null)
  445. {
  446. if (ActiveDocumentPane == null)
  447. value = DockPanel.DockWindows[DockState.Document].DefaultPane;
  448. else if (ActiveDocumentPane.DockPanel != DockPanel || ActiveDocumentPane.DockState != DockState.Document)
  449. value = DockPanel.DockWindows[DockState.Document].DefaultPane;
  450. else
  451. value = ActiveDocumentPane;
  452. }
  453. if (m_activeDocumentPane == value)
  454. return;
  455. if (m_activeDocumentPane != null)
  456. m_activeDocumentPane.SetIsActiveDocumentPane(false);
  457. m_activeDocumentPane = value;
  458. if (m_activeDocumentPane != null)
  459. m_activeDocumentPane.SetIsActiveDocumentPane(true);
  460. }
  461. private IDockContent m_activeDocument = null;
  462. public IDockContent ActiveDocument
  463. {
  464. get
  465. {
  466. return m_activeDocument;
  467. }
  468. }
  469. private void SetActiveDocument()
  470. {
  471. IDockContent value = ActiveDocumentPane == null ? null : ActiveDocumentPane.ActiveContent;
  472. if (m_activeDocument == value)
  473. return;
  474. m_activeDocument = value;
  475. }
  476. }
  477. private IFocusManager FocusManager
  478. {
  479. get
  480. {
  481. return m_focusManager;
  482. }
  483. }
  484. internal IContentFocusManager ContentFocusManager
  485. {
  486. get
  487. {
  488. return m_focusManager;
  489. }
  490. }
  491. internal void SaveFocus()
  492. {
  493. DummyControl.Focus();
  494. }
  495. [Browsable(false)]
  496. public IDockContent ActiveContent
  497. {
  498. get
  499. {
  500. return FocusManager.ActiveContent;
  501. }
  502. }
  503. [Browsable(false)]
  504. public DockPane ActivePane
  505. {
  506. get
  507. {
  508. return FocusManager.ActivePane;
  509. }
  510. }
  511. [Browsable(false)]
  512. public IDockContent ActiveDocument
  513. {
  514. get
  515. {
  516. return FocusManager.ActiveDocument;
  517. }
  518. }
  519. [Browsable(false)]
  520. public DockPane ActiveDocumentPane
  521. {
  522. get
  523. {
  524. return FocusManager.ActiveDocumentPane;
  525. }
  526. }
  527. private static readonly object ActiveDocumentChangedEvent = new object();
  528. [LocalizedCategory("Category_PropertyChanged")]
  529. [LocalizedDescription("DockPanel_ActiveDocumentChanged_Description")]
  530. public event EventHandler ActiveDocumentChanged
  531. {
  532. add
  533. {
  534. Events.AddHandler(ActiveDocumentChangedEvent, value);
  535. }
  536. remove
  537. {
  538. Events.RemoveHandler(ActiveDocumentChangedEvent, value);
  539. }
  540. }
  541. protected virtual void OnActiveDocumentChanged(EventArgs e)
  542. {
  543. EventHandler handler = (EventHandler)Events[ActiveDocumentChangedEvent];
  544. if (handler != null)
  545. handler(this, e);
  546. }
  547. private static readonly object ActiveContentChangedEvent = new object();
  548. [LocalizedCategory("Category_PropertyChanged")]
  549. [LocalizedDescription("DockPanel_ActiveContentChanged_Description")]
  550. public event EventHandler ActiveContentChanged
  551. {
  552. add
  553. {
  554. Events.AddHandler(ActiveContentChangedEvent, value);
  555. }
  556. remove
  557. {
  558. Events.RemoveHandler(ActiveContentChangedEvent, value);
  559. }
  560. }
  561. protected void OnActiveContentChanged(EventArgs e)
  562. {
  563. EventHandler handler = (EventHandler)Events[ActiveContentChangedEvent];
  564. if (handler != null)
  565. handler(this, e);
  566. }
  567. private static readonly object ActivePaneChangedEvent = new object();
  568. [LocalizedCategory("Category_PropertyChanged")]
  569. [LocalizedDescription("DockPanel_ActivePaneChanged_Description")]
  570. public event EventHandler ActivePaneChanged
  571. {
  572. add
  573. {
  574. Events.AddHandler(ActivePaneChangedEvent, value);
  575. }
  576. remove
  577. {
  578. Events.RemoveHandler(ActivePaneChangedEvent, value);
  579. }
  580. }
  581. protected virtual void OnActivePaneChanged(EventArgs e)
  582. {
  583. EventHandler handler = (EventHandler)Events[ActivePaneChangedEvent];
  584. if (handler != null)
  585. handler(this, e);
  586. }
  587. }
  588. }