LayoutFloatingWindowControl.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  1. /*************************************************************************************
  2. Extended WPF Toolkit
  3. Copyright (C) 2007-2013 Xceed Software Inc.
  4. This program is provided to you under the terms of the Microsoft Public
  5. License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
  6. For more features, controls, and fast professional support,
  7. pick up the Plus Edition at http://xceed.com/wpf_toolkit
  8. Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids
  9. ***********************************************************************************/
  10. using System;
  11. using System.Collections.Generic;
  12. using System.Linq;
  13. using System.Text;
  14. using System.Windows;
  15. using System.Runtime.InteropServices;
  16. using System.Windows.Interop;
  17. using System.Windows.Input;
  18. using System.Windows.Controls;
  19. using System.Windows.Data;
  20. using System.Windows.Media;
  21. using Xceed.Wpf.AvalonDock.Layout;
  22. using System.Diagnostics;
  23. using System.Windows.Documents;
  24. using Xceed.Wpf.AvalonDock.Themes;
  25. namespace Xceed.Wpf.AvalonDock.Controls
  26. {
  27. public abstract class LayoutFloatingWindowControl : Window, ILayoutControl
  28. {
  29. private ResourceDictionary currentThemeResourceDictionary; // = null
  30. static LayoutFloatingWindowControl()
  31. {
  32. LayoutFloatingWindowControl.ContentProperty.OverrideMetadata(typeof(LayoutFloatingWindowControl), new FrameworkPropertyMetadata(null, null, new CoerceValueCallback(CoerceContentValue)));
  33. AllowsTransparencyProperty.OverrideMetadata(typeof(LayoutFloatingWindowControl), new FrameworkPropertyMetadata(false));
  34. ShowInTaskbarProperty.OverrideMetadata(typeof(LayoutFloatingWindowControl), new FrameworkPropertyMetadata(false));
  35. }
  36. static object CoerceContentValue(DependencyObject sender, object content)
  37. {
  38. return new FloatingWindowContentHost(sender as LayoutFloatingWindowControl) { Content = content as UIElement };
  39. }
  40. protected class FloatingWindowContentHost : HwndHost
  41. {
  42. LayoutFloatingWindowControl _owner;
  43. public FloatingWindowContentHost(LayoutFloatingWindowControl owner)
  44. {
  45. _owner = owner;
  46. var manager = _owner.Model.Root.Manager;
  47. }
  48. HwndSource _wpfContentHost = null;
  49. Border _rootPresenter = null;
  50. DockingManager _manager = null;
  51. protected override System.Runtime.InteropServices.HandleRef BuildWindowCore(System.Runtime.InteropServices.HandleRef hwndParent)
  52. {
  53. _wpfContentHost = new HwndSource(new HwndSourceParameters()
  54. {
  55. ParentWindow = hwndParent.Handle,
  56. WindowStyle = Win32Helper.WS_CHILD | Win32Helper.WS_VISIBLE | Win32Helper.WS_CLIPSIBLINGS | Win32Helper.WS_CLIPCHILDREN,
  57. Width = 1,
  58. Height = 1
  59. });
  60. _rootPresenter = new Border() { Child = new AdornerDecorator() { Child = Content }, Focusable = true };
  61. _rootPresenter.SetBinding(Border.BackgroundProperty, new Binding("Background") { Source = _owner });
  62. _wpfContentHost.RootVisual = _rootPresenter;
  63. _wpfContentHost.SizeToContent = SizeToContent.Manual;
  64. _manager = _owner.Model.Root.Manager;
  65. _manager.InternalAddLogicalChild(_rootPresenter);
  66. return new HandleRef(this, _wpfContentHost.Handle);
  67. }
  68. protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e)
  69. {
  70. Trace.WriteLine("FloatingWindowContentHost.GotKeyboardFocus");
  71. base.OnGotKeyboardFocus(e);
  72. }
  73. protected override void DestroyWindowCore(HandleRef hwnd)
  74. {
  75. _manager.InternalRemoveLogicalChild(_rootPresenter);
  76. if (_wpfContentHost != null)
  77. {
  78. _wpfContentHost.Dispose();
  79. _wpfContentHost = null;
  80. }
  81. }
  82. protected override IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
  83. {
  84. switch (msg)
  85. {
  86. case Win32Helper.WM_SETFOCUS:
  87. Trace.WriteLine("FloatingWindowContentHost.WM_SETFOCUS");
  88. break;
  89. case Win32Helper.WM_KILLFOCUS:
  90. Trace.WriteLine("FloatingWindowContentHost.WM_KILLFOCUS");
  91. break;
  92. }
  93. return base.WndProc(hwnd, msg, wParam, lParam, ref handled);
  94. }
  95. public Visual RootVisual
  96. {
  97. get { return _rootPresenter; }
  98. }
  99. protected override Size MeasureOverride(Size constraint)
  100. {
  101. if (Content == null)
  102. return base.MeasureOverride(constraint);
  103. Content.Measure(constraint);
  104. return Content.DesiredSize;
  105. }
  106. #region Content
  107. /// <summary>
  108. /// Content Dependency Property
  109. /// </summary>
  110. public static readonly DependencyProperty ContentProperty =
  111. DependencyProperty.Register("Content", typeof(UIElement), typeof(FloatingWindowContentHost),
  112. new FrameworkPropertyMetadata((UIElement)null,
  113. new PropertyChangedCallback(OnContentChanged)));
  114. /// <summary>
  115. /// Gets or sets the Content property. This dependency property
  116. /// indicates ....
  117. /// </summary>
  118. public UIElement Content
  119. {
  120. get { return (UIElement)GetValue(ContentProperty); }
  121. set { SetValue(ContentProperty, value); }
  122. }
  123. /// <summary>
  124. /// Handles changes to the Content property.
  125. /// </summary>
  126. private static void OnContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  127. {
  128. ((FloatingWindowContentHost)d).OnContentChanged(e);
  129. }
  130. /// <summary>
  131. /// Provides derived classes an opportunity to handle changes to the Content property.
  132. /// </summary>
  133. protected virtual void OnContentChanged(DependencyPropertyChangedEventArgs e)
  134. {
  135. if (_rootPresenter != null)
  136. _rootPresenter.Child = Content;
  137. }
  138. #endregion
  139. }
  140. ILayoutElement _model;
  141. protected LayoutFloatingWindowControl(ILayoutElement model)
  142. {
  143. this.Loaded += new RoutedEventHandler(OnLoaded);
  144. this.Unloaded += new RoutedEventHandler(OnUnloaded);
  145. _model = model;
  146. UpdateThemeResources();
  147. }
  148. internal virtual void UpdateThemeResources(Theme oldTheme = null)
  149. {
  150. if (oldTheme != null)
  151. {
  152. if( oldTheme is DictionaryTheme )
  153. {
  154. if( currentThemeResourceDictionary != null )
  155. {
  156. Resources.MergedDictionaries.Remove( currentThemeResourceDictionary );
  157. currentThemeResourceDictionary = null;
  158. }
  159. }
  160. else
  161. {
  162. var resourceDictionaryToRemove =
  163. Resources.MergedDictionaries.FirstOrDefault( r => r.Source == oldTheme.GetResourceUri() );
  164. if( resourceDictionaryToRemove != null )
  165. Resources.MergedDictionaries.Remove(
  166. resourceDictionaryToRemove );
  167. }
  168. }
  169. var manager = _model.Root.Manager;
  170. if (manager.Theme != null)
  171. {
  172. if( manager.Theme is DictionaryTheme )
  173. {
  174. currentThemeResourceDictionary = ( ( DictionaryTheme )manager.Theme ).ThemeResourceDictionary;
  175. Resources.MergedDictionaries.Add( currentThemeResourceDictionary );
  176. }
  177. else
  178. {
  179. Resources.MergedDictionaries.Add(new ResourceDictionary() { Source = manager.Theme.GetResourceUri() });
  180. }
  181. }
  182. }
  183. protected override void OnClosed(EventArgs e)
  184. {
  185. if (Content != null)
  186. {
  187. var host = Content as FloatingWindowContentHost;
  188. host.Dispose();
  189. if (_hwndSrc != null)
  190. {
  191. _hwndSrc.RemoveHook(_hwndSrcHook);
  192. _hwndSrc.Dispose();
  193. _hwndSrc = null;
  194. }
  195. }
  196. base.OnClosed(e);
  197. }
  198. bool _attachDrag = false;
  199. internal void AttachDrag(bool onActivated = true)
  200. {
  201. if (onActivated)
  202. {
  203. _attachDrag = true;
  204. this.Activated += new EventHandler(OnActivated);
  205. }
  206. else
  207. {
  208. IntPtr windowHandle = new WindowInteropHelper(this).Handle;
  209. IntPtr lParam = new IntPtr(((int)Left & (int)0xFFFF) | (((int)Top) << 16));
  210. Win32Helper.SendMessage(windowHandle, Win32Helper.WM_NCLBUTTONDOWN, new IntPtr(Win32Helper.HT_CAPTION), lParam);
  211. }
  212. }
  213. HwndSource _hwndSrc;
  214. HwndSourceHook _hwndSrcHook;
  215. void OnLoaded(object sender, RoutedEventArgs e)
  216. {
  217. this.Loaded -= new RoutedEventHandler(OnLoaded);
  218. this.SetParentToMainWindowOf(Model.Root.Manager);
  219. _hwndSrc = HwndSource.FromDependencyObject(this) as HwndSource;
  220. _hwndSrcHook = new HwndSourceHook(FilterMessage);
  221. _hwndSrc.AddHook(_hwndSrcHook);
  222. }
  223. void OnUnloaded(object sender, RoutedEventArgs e)
  224. {
  225. this.Unloaded -= new RoutedEventHandler(OnUnloaded);
  226. if (_hwndSrc != null)
  227. {
  228. _hwndSrc.RemoveHook(_hwndSrcHook);
  229. _hwndSrc.Dispose();
  230. _hwndSrc = null;
  231. }
  232. }
  233. void OnActivated(object sender, EventArgs e)
  234. {
  235. this.Activated -= new EventHandler(OnActivated);
  236. if (_attachDrag && Mouse.LeftButton == MouseButtonState.Pressed)
  237. {
  238. IntPtr windowHandle = new WindowInteropHelper(this).Handle;
  239. var mousePosition = this.PointToScreenDPI(Mouse.GetPosition(this));
  240. var clientArea = Win32Helper.GetClientRect(windowHandle);
  241. var windowArea = Win32Helper.GetWindowRect(windowHandle);
  242. Left = mousePosition.X - windowArea.Width / 2.0;
  243. Top = mousePosition.Y - (windowArea.Height - clientArea.Height) / 2.0;
  244. _attachDrag = false;
  245. IntPtr lParam = new IntPtr(((int)mousePosition.X & (int)0xFFFF) | (((int)mousePosition.Y) << 16));
  246. Win32Helper.SendMessage(windowHandle, Win32Helper.WM_NCLBUTTONDOWN, new IntPtr(Win32Helper.HT_CAPTION), lParam);
  247. }
  248. }
  249. protected override void OnInitialized(EventArgs e)
  250. {
  251. CommandBindings.Add(new CommandBinding(Microsoft.Windows.Shell.SystemCommands.CloseWindowCommand,
  252. new ExecutedRoutedEventHandler((s, args) => Microsoft.Windows.Shell.SystemCommands.CloseWindow((Window)args.Parameter))));
  253. CommandBindings.Add(new CommandBinding(Microsoft.Windows.Shell.SystemCommands.MaximizeWindowCommand,
  254. new ExecutedRoutedEventHandler((s, args) => Microsoft.Windows.Shell.SystemCommands.MaximizeWindow((Window)args.Parameter))));
  255. CommandBindings.Add(new CommandBinding(Microsoft.Windows.Shell.SystemCommands.MinimizeWindowCommand,
  256. new ExecutedRoutedEventHandler((s, args) => Microsoft.Windows.Shell.SystemCommands.MinimizeWindow((Window)args.Parameter))));
  257. CommandBindings.Add(new CommandBinding(Microsoft.Windows.Shell.SystemCommands.RestoreWindowCommand,
  258. new ExecutedRoutedEventHandler((s, args) => Microsoft.Windows.Shell.SystemCommands.RestoreWindow((Window)args.Parameter))));
  259. //Debug.Assert(this.Owner != null);
  260. base.OnInitialized(e);
  261. }
  262. public abstract ILayoutElement Model { get; }
  263. #region IsDragging
  264. /// <summary>
  265. /// IsDragging Read-Only Dependency Property
  266. /// </summary>
  267. private static readonly DependencyPropertyKey IsDraggingPropertyKey
  268. = DependencyProperty.RegisterReadOnly("IsDragging", typeof(bool), typeof(LayoutFloatingWindowControl),
  269. new FrameworkPropertyMetadata((bool)false,
  270. new PropertyChangedCallback(OnIsDraggingChanged)));
  271. public static readonly DependencyProperty IsDraggingProperty
  272. = IsDraggingPropertyKey.DependencyProperty;
  273. /// <summary>
  274. /// Gets the IsDragging property. This dependency property
  275. /// indicates that this floating window is being dragged.
  276. /// </summary>
  277. public bool IsDragging
  278. {
  279. get { return (bool)GetValue(IsDraggingProperty); }
  280. }
  281. /// <summary>
  282. /// Provides a secure method for setting the IsDragging property.
  283. /// This dependency property indicates that this floating window is being dragged.
  284. /// </summary>
  285. /// <param name="value">The new value for the property.</param>
  286. protected void SetIsDragging(bool value)
  287. {
  288. SetValue(IsDraggingPropertyKey, value);
  289. }
  290. /// <summary>
  291. /// Handles changes to the IsDragging property.
  292. /// </summary>
  293. private static void OnIsDraggingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  294. {
  295. ((LayoutFloatingWindowControl)d).OnIsDraggingChanged(e);
  296. }
  297. /// <summary>
  298. /// Provides derived classes an opportunity to handle changes to the IsDragging property.
  299. /// </summary>
  300. protected virtual void OnIsDraggingChanged(DependencyPropertyChangedEventArgs e)
  301. {
  302. //Trace.WriteLine("IsDragging={0}", e.NewValue);
  303. }
  304. #endregion
  305. DragService _dragService = null;
  306. void UpdatePositionAndSizeOfPanes()
  307. {
  308. foreach (var posElement in Model.Descendents().OfType<ILayoutElementForFloatingWindow>())
  309. {
  310. posElement.FloatingLeft = Left;
  311. posElement.FloatingTop = Top;
  312. posElement.FloatingWidth = Width;
  313. posElement.FloatingHeight = Height;
  314. }
  315. }
  316. void UpdateMaximizedState( bool isMaximized )
  317. {
  318. foreach( var posElement in Model.Descendents().OfType<ILayoutElementForFloatingWindow>() )
  319. {
  320. posElement.IsMaximized = isMaximized;
  321. }
  322. }
  323. protected virtual IntPtr FilterMessage(
  324. IntPtr hwnd,
  325. int msg,
  326. IntPtr wParam,
  327. IntPtr lParam,
  328. ref bool handled
  329. )
  330. {
  331. handled = false;
  332. switch (msg)
  333. {
  334. case Win32Helper.WM_ACTIVATE:
  335. if (((int)wParam & 0xFFFF) == Win32Helper.WA_INACTIVE)
  336. {
  337. if (lParam == this.GetParentWindowHandle())
  338. {
  339. Win32Helper.SetActiveWindow(_hwndSrc.Handle);
  340. handled = true;
  341. }
  342. }
  343. break;
  344. case Win32Helper.WM_EXITSIZEMOVE:
  345. UpdatePositionAndSizeOfPanes();
  346. if (_dragService != null)
  347. {
  348. bool dropFlag;
  349. var mousePosition = this.TransformToDeviceDPI(Win32Helper.GetMousePosition());
  350. _dragService.Drop(mousePosition, out dropFlag);
  351. _dragService = null;
  352. SetIsDragging(false);
  353. if (dropFlag)
  354. InternalClose();
  355. }
  356. break;
  357. case Win32Helper.WM_MOVING:
  358. {
  359. UpdateDragPosition();
  360. }
  361. break;
  362. case Win32Helper.WM_LBUTTONUP: //set as handled right button click on title area (after showing context menu)
  363. if (_dragService != null && Mouse.LeftButton == MouseButtonState.Released)
  364. {
  365. _dragService.Abort();
  366. _dragService = null;
  367. SetIsDragging(false);
  368. }
  369. break;
  370. case Win32Helper.WM_SYSCOMMAND:
  371. IntPtr wMaximize = new IntPtr( Win32Helper.SC_MAXIMIZE );
  372. IntPtr wRestore = new IntPtr( Win32Helper.SC_RESTORE );
  373. if( wParam == wMaximize || wParam == wRestore )
  374. {
  375. UpdateMaximizedState( wParam == wMaximize );
  376. }
  377. break;
  378. }
  379. return IntPtr.Zero;
  380. }
  381. private void UpdateDragPosition()
  382. {
  383. if (_dragService == null)
  384. {
  385. _dragService = new DragService(this);
  386. SetIsDragging(true);
  387. }
  388. var mousePosition = this.TransformToDeviceDPI(Win32Helper.GetMousePosition());
  389. _dragService.UpdateMouseLocation(mousePosition);
  390. }
  391. bool _internalCloseFlag = false;
  392. internal void InternalClose()
  393. {
  394. _internalCloseFlag = true;
  395. Close();
  396. }
  397. protected bool CloseInitiatedByUser
  398. {
  399. get { return !_internalCloseFlag; }
  400. }
  401. internal bool KeepContentVisibleOnClose
  402. {
  403. get;
  404. set;
  405. }
  406. protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
  407. {
  408. base.OnMouseLeftButtonUp(e);
  409. }
  410. #region IsMaximized
  411. /// <summary>
  412. /// IsMaximized Read-Only Dependency Property
  413. /// </summary>
  414. private static readonly DependencyPropertyKey IsMaximizedPropertyKey
  415. = DependencyProperty.RegisterReadOnly("IsMaximized", typeof(bool), typeof(LayoutFloatingWindowControl),
  416. new FrameworkPropertyMetadata((bool)false));
  417. public static readonly DependencyProperty IsMaximizedProperty
  418. = IsMaximizedPropertyKey.DependencyProperty;
  419. /// <summary>
  420. /// Gets the IsMaximized property. This dependency property
  421. /// indicates if the window is maximized.
  422. /// </summary>
  423. public bool IsMaximized
  424. {
  425. get { return (bool)GetValue(IsMaximizedProperty); }
  426. }
  427. /// <summary>
  428. /// Provides a secure method for setting the IsMaximized property.
  429. /// This dependency property indicates if the window is maximized.
  430. /// </summary>
  431. /// <param name="value">The new value for the property.</param>
  432. protected void SetIsMaximized(bool value)
  433. {
  434. SetValue(IsMaximizedPropertyKey, value);
  435. }
  436. protected override void OnStateChanged(EventArgs e)
  437. {
  438. SetIsMaximized(WindowState == System.Windows.WindowState.Maximized);
  439. base.OnStateChanged(e);
  440. }
  441. #endregion
  442. }
  443. }