/Main/Source/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Layout/LayoutAnchorable.cs

# · C# · 655 lines · 528 code · 89 blank · 38 comment · 122 complexity · 2fa7eb4b9f9b9bea3b3d7b9c0339c613 MD5 · raw file

  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.Xml.Serialization;
  16. using System.Windows.Controls;
  17. using System.Globalization;
  18. using System.ComponentModel;
  19. namespace Xceed.Wpf.AvalonDock.Layout
  20. {
  21. [Serializable]
  22. public class LayoutAnchorable : LayoutContent
  23. {
  24. #region IsVisible
  25. [XmlIgnore]
  26. public bool IsVisible
  27. {
  28. get
  29. {
  30. return Parent != null && !(Parent is LayoutRoot);
  31. }
  32. set
  33. {
  34. if (value)
  35. {
  36. Show();
  37. }
  38. else
  39. {
  40. Hide();
  41. }
  42. }
  43. }
  44. public event EventHandler IsVisibleChanged;
  45. void NotifyIsVisibleChanged()
  46. {
  47. if (IsVisibleChanged != null)
  48. IsVisibleChanged(this, EventArgs.Empty);
  49. }
  50. [XmlIgnore]
  51. public bool IsHidden
  52. {
  53. get
  54. {
  55. return (Parent is LayoutRoot);
  56. }
  57. }
  58. protected override void OnParentChanged(ILayoutContainer oldValue, ILayoutContainer newValue)
  59. {
  60. UpdateParentVisibility();
  61. RaisePropertyChanged("IsVisible");
  62. NotifyIsVisibleChanged();
  63. RaisePropertyChanged("IsHidden");
  64. RaisePropertyChanged("IsAutoHidden");
  65. base.OnParentChanged(oldValue, newValue);
  66. }
  67. void UpdateParentVisibility()
  68. {
  69. var parentPane = Parent as ILayoutElementWithVisibility;
  70. if (parentPane != null)
  71. parentPane.ComputeVisibility();
  72. }
  73. #endregion
  74. #region AutoHideWidth
  75. private double _autohideWidth = 0.0;
  76. public double AutoHideWidth
  77. {
  78. get { return _autohideWidth; }
  79. set
  80. {
  81. if (_autohideWidth != value)
  82. {
  83. RaisePropertyChanging("AutoHideWidth");
  84. value = Math.Max(value, _autohideMinWidth);
  85. _autohideWidth = value;
  86. RaisePropertyChanged("AutoHideWidth");
  87. }
  88. }
  89. }
  90. #endregion
  91. #region AutoHideMinWidth
  92. private double _autohideMinWidth = 100.0;
  93. public double AutoHideMinWidth
  94. {
  95. get { return _autohideMinWidth; }
  96. set
  97. {
  98. if (_autohideMinWidth != value)
  99. {
  100. RaisePropertyChanging("AutoHideMinWidth");
  101. if (value < 0)
  102. throw new ArgumentException("value");
  103. _autohideMinWidth = value;
  104. RaisePropertyChanged("AutoHideMinWidth");
  105. }
  106. }
  107. }
  108. #endregion
  109. #region AutoHideHeight
  110. private double _autohideHeight = 0.0;
  111. public double AutoHideHeight
  112. {
  113. get { return _autohideHeight; }
  114. set
  115. {
  116. if (_autohideHeight != value)
  117. {
  118. RaisePropertyChanging("AutoHideHeight");
  119. value = Math.Max(value, _autohideMinHeight);
  120. _autohideHeight = value;
  121. RaisePropertyChanged("AutoHideHeight");
  122. }
  123. }
  124. }
  125. #endregion
  126. #region AutoHideMinHeight
  127. private double _autohideMinHeight = 100.0;
  128. public double AutoHideMinHeight
  129. {
  130. get { return _autohideMinHeight; }
  131. set
  132. {
  133. if (_autohideMinHeight != value)
  134. {
  135. RaisePropertyChanging("AutoHideMinHeight");
  136. if (value < 0)
  137. throw new ArgumentException("value");
  138. _autohideMinHeight = value;
  139. RaisePropertyChanged("AutoHideMinHeight");
  140. }
  141. }
  142. }
  143. #endregion
  144. /// <summary>
  145. /// Hide this contents
  146. /// </summary>
  147. /// <remarks>Add this content to <see cref="ILayoutRoot.Hidden"/> collection of parent root.</remarks>
  148. public void Hide(bool cancelable = true)
  149. {
  150. if (!IsVisible)
  151. {
  152. IsSelected = true;
  153. IsActive = true;
  154. return;
  155. }
  156. if (cancelable)
  157. {
  158. CancelEventArgs args = new CancelEventArgs();
  159. OnHiding(args);
  160. if (args.Cancel)
  161. return;
  162. }
  163. RaisePropertyChanging("IsHidden");
  164. RaisePropertyChanging("IsVisible");
  165. //if (Parent is ILayoutPane)
  166. {
  167. var parentAsGroup = Parent as ILayoutGroup;
  168. PreviousContainer = parentAsGroup;
  169. PreviousContainerIndex = parentAsGroup.IndexOfChild(this);
  170. }
  171. Root.Hidden.Add(this);
  172. RaisePropertyChanged("IsVisible");
  173. RaisePropertyChanged("IsHidden");
  174. NotifyIsVisibleChanged();
  175. }
  176. public event EventHandler<CancelEventArgs> Hiding;
  177. protected virtual void OnHiding(CancelEventArgs args)
  178. {
  179. if (Hiding != null)
  180. Hiding(this, args);
  181. }
  182. /// <summary>
  183. /// Show the content
  184. /// </summary>
  185. /// <remarks>Try to show the content where it was previously hidden.</remarks>
  186. public void Show()
  187. {
  188. if (IsVisible)
  189. return;
  190. if (!IsHidden)
  191. throw new InvalidOperationException();
  192. RaisePropertyChanging("IsHidden");
  193. RaisePropertyChanging("IsVisible");
  194. bool added = false;
  195. var root = Root;
  196. if (root != null && root.Manager != null)
  197. {
  198. if (root.Manager.LayoutUpdateStrategy != null)
  199. added = root.Manager.LayoutUpdateStrategy.BeforeInsertAnchorable(root as LayoutRoot, this, PreviousContainer);
  200. }
  201. if (!added && PreviousContainer != null)
  202. {
  203. var previousContainerAsLayoutGroup = PreviousContainer as ILayoutGroup;
  204. if (PreviousContainerIndex < previousContainerAsLayoutGroup.ChildrenCount)
  205. previousContainerAsLayoutGroup.InsertChildAt(PreviousContainerIndex, this);
  206. else
  207. previousContainerAsLayoutGroup.InsertChildAt(previousContainerAsLayoutGroup.ChildrenCount, this);
  208. IsSelected = true;
  209. IsActive = true;
  210. }
  211. if (root != null && root.Manager != null)
  212. {
  213. if (root.Manager.LayoutUpdateStrategy != null)
  214. {
  215. root.Manager.LayoutUpdateStrategy.AfterInsertAnchorable(root as LayoutRoot, this);
  216. }
  217. }
  218. PreviousContainer = null;
  219. PreviousContainerIndex = -1;
  220. RaisePropertyChanged("IsVisible");
  221. RaisePropertyChanged("IsHidden");
  222. NotifyIsVisibleChanged();
  223. }
  224. protected override void InternalDock()
  225. {
  226. var root = Root as LayoutRoot;
  227. LayoutAnchorablePane anchorablePane = null;
  228. if (root.ActiveContent != null &&
  229. root.ActiveContent != this)
  230. {
  231. //look for active content parent pane
  232. anchorablePane = root.ActiveContent.Parent as LayoutAnchorablePane;
  233. }
  234. if (anchorablePane == null)
  235. {
  236. //look for a pane on the right side
  237. anchorablePane = root.Descendents().OfType<LayoutAnchorablePane>().Where(pane => !pane.IsHostedInFloatingWindow && pane.GetSide() == AnchorSide.Right).FirstOrDefault();
  238. }
  239. if (anchorablePane == null)
  240. {
  241. //look for an available pane
  242. anchorablePane = root.Descendents().OfType<LayoutAnchorablePane>().FirstOrDefault();
  243. }
  244. bool added = false;
  245. if (root.Manager.LayoutUpdateStrategy != null)
  246. {
  247. added = root.Manager.LayoutUpdateStrategy.BeforeInsertAnchorable(root, this, anchorablePane);
  248. }
  249. if (!added)
  250. {
  251. if (anchorablePane == null)
  252. {
  253. var mainLayoutPanel = new LayoutPanel() { Orientation = Orientation.Horizontal };
  254. if (root.RootPanel != null)
  255. {
  256. mainLayoutPanel.Children.Add(root.RootPanel);
  257. }
  258. root.RootPanel = mainLayoutPanel;
  259. anchorablePane = new LayoutAnchorablePane() { DockWidth = new GridLength(200.0, GridUnitType.Pixel) };
  260. mainLayoutPanel.Children.Add(anchorablePane);
  261. }
  262. anchorablePane.Children.Add(this);
  263. added = true;
  264. }
  265. if (root.Manager.LayoutUpdateStrategy != null)
  266. {
  267. root.Manager.LayoutUpdateStrategy.AfterInsertAnchorable(root, this);
  268. }
  269. base.InternalDock();
  270. }
  271. /// <summary>
  272. /// Add the anchorable to a DockingManager layout
  273. /// </summary>
  274. /// <param name="manager"></param>
  275. /// <param name="strategy"></param>
  276. public void AddToLayout(DockingManager manager, AnchorableShowStrategy strategy)
  277. {
  278. if (IsVisible ||
  279. IsHidden)
  280. throw new InvalidOperationException();
  281. bool most = (strategy & AnchorableShowStrategy.Most) == AnchorableShowStrategy.Most;
  282. bool left = (strategy & AnchorableShowStrategy.Left) == AnchorableShowStrategy.Left;
  283. bool right = (strategy & AnchorableShowStrategy.Right) == AnchorableShowStrategy.Right;
  284. bool top = (strategy & AnchorableShowStrategy.Top) == AnchorableShowStrategy.Top;
  285. bool bottom = (strategy & AnchorableShowStrategy.Bottom) == AnchorableShowStrategy.Bottom;
  286. if (!most)
  287. {
  288. var side = AnchorSide.Left;
  289. if (left)
  290. side = AnchorSide.Left;
  291. if (right)
  292. side = AnchorSide.Right;
  293. if (top)
  294. side = AnchorSide.Top;
  295. if (bottom)
  296. side = AnchorSide.Bottom;
  297. var anchorablePane = manager.Layout.Descendents().OfType<LayoutAnchorablePane>().FirstOrDefault(p => p.GetSide() == side);
  298. if (anchorablePane != null)
  299. anchorablePane.Children.Add(this);
  300. else
  301. most = true;
  302. }
  303. if (most)
  304. {
  305. if (manager.Layout.RootPanel == null)
  306. manager.Layout.RootPanel = new LayoutPanel() { Orientation = (left || right ? Orientation.Horizontal : Orientation.Vertical) };
  307. if (left || right)
  308. {
  309. if (manager.Layout.RootPanel.Orientation == Orientation.Vertical &&
  310. manager.Layout.RootPanel.ChildrenCount > 1)
  311. {
  312. manager.Layout.RootPanel = new LayoutPanel(manager.Layout.RootPanel);
  313. }
  314. manager.Layout.RootPanel.Orientation = Orientation.Horizontal;
  315. if (left)
  316. manager.Layout.RootPanel.Children.Insert(0, new LayoutAnchorablePane(this));
  317. else
  318. manager.Layout.RootPanel.Children.Add(new LayoutAnchorablePane(this));
  319. }
  320. else
  321. {
  322. if (manager.Layout.RootPanel.Orientation == Orientation.Horizontal &&
  323. manager.Layout.RootPanel.ChildrenCount > 1)
  324. {
  325. manager.Layout.RootPanel = new LayoutPanel(manager.Layout.RootPanel);
  326. }
  327. manager.Layout.RootPanel.Orientation = Orientation.Vertical;
  328. if (top)
  329. manager.Layout.RootPanel.Children.Insert(0, new LayoutAnchorablePane(this));
  330. else
  331. manager.Layout.RootPanel.Children.Add(new LayoutAnchorablePane(this));
  332. }
  333. }
  334. }
  335. /// <summary>
  336. /// Get a value indicating if the anchorable is anchored to a border in an autohide status
  337. /// </summary>
  338. public bool IsAutoHidden
  339. {
  340. get { return Parent != null && Parent is LayoutAnchorGroup; }
  341. }
  342. #region AutoHide
  343. public void ToggleAutoHide()
  344. {
  345. #region Anchorable is already auto hidden
  346. if (IsAutoHidden)
  347. {
  348. var parentGroup = Parent as LayoutAnchorGroup;
  349. var parentSide = parentGroup.Parent as LayoutAnchorSide;
  350. var previousContainer = ((ILayoutPreviousContainer)parentGroup).PreviousContainer as LayoutAnchorablePane;
  351. if (previousContainer == null)
  352. {
  353. AnchorSide side = (parentGroup.Parent as LayoutAnchorSide).Side;
  354. switch (side)
  355. {
  356. case AnchorSide.Right:
  357. if (parentGroup.Root.RootPanel.Orientation == Orientation.Horizontal)
  358. {
  359. previousContainer = new LayoutAnchorablePane();
  360. previousContainer.DockMinWidth = this.AutoHideMinWidth;
  361. parentGroup.Root.RootPanel.Children.Add(previousContainer);
  362. }
  363. else
  364. {
  365. previousContainer = new LayoutAnchorablePane();
  366. LayoutPanel panel = new LayoutPanel() { Orientation = Orientation.Horizontal };
  367. LayoutRoot root = parentGroup.Root as LayoutRoot;
  368. LayoutPanel oldRootPanel = parentGroup.Root.RootPanel as LayoutPanel;
  369. root.RootPanel = panel;
  370. panel.Children.Add(oldRootPanel);
  371. panel.Children.Add(previousContainer);
  372. }
  373. break;
  374. case AnchorSide.Left:
  375. if (parentGroup.Root.RootPanel.Orientation == Orientation.Horizontal)
  376. {
  377. previousContainer = new LayoutAnchorablePane();
  378. previousContainer.DockMinWidth = this.AutoHideMinWidth;
  379. parentGroup.Root.RootPanel.Children.Insert(0, previousContainer);
  380. }
  381. else
  382. {
  383. previousContainer = new LayoutAnchorablePane();
  384. LayoutPanel panel = new LayoutPanel() { Orientation = Orientation.Horizontal };
  385. LayoutRoot root = parentGroup.Root as LayoutRoot;
  386. LayoutPanel oldRootPanel = parentGroup.Root.RootPanel as LayoutPanel;
  387. root.RootPanel = panel;
  388. panel.Children.Add(previousContainer);
  389. panel.Children.Add(oldRootPanel);
  390. }
  391. break;
  392. case AnchorSide.Top:
  393. if (parentGroup.Root.RootPanel.Orientation == Orientation.Vertical)
  394. {
  395. previousContainer = new LayoutAnchorablePane();
  396. previousContainer.DockMinHeight = this.AutoHideMinHeight;
  397. parentGroup.Root.RootPanel.Children.Insert(0, previousContainer);
  398. }
  399. else
  400. {
  401. previousContainer = new LayoutAnchorablePane();
  402. LayoutPanel panel = new LayoutPanel() { Orientation = Orientation.Vertical };
  403. LayoutRoot root = parentGroup.Root as LayoutRoot;
  404. LayoutPanel oldRootPanel = parentGroup.Root.RootPanel as LayoutPanel;
  405. root.RootPanel = panel;
  406. panel.Children.Add(previousContainer);
  407. panel.Children.Add(oldRootPanel);
  408. }
  409. break;
  410. case AnchorSide.Bottom:
  411. if (parentGroup.Root.RootPanel.Orientation == Orientation.Vertical)
  412. {
  413. previousContainer = new LayoutAnchorablePane();
  414. previousContainer.DockMinHeight = this.AutoHideMinHeight;
  415. parentGroup.Root.RootPanel.Children.Add(previousContainer);
  416. }
  417. else
  418. {
  419. previousContainer = new LayoutAnchorablePane();
  420. LayoutPanel panel = new LayoutPanel() { Orientation = Orientation.Vertical };
  421. LayoutRoot root = parentGroup.Root as LayoutRoot;
  422. LayoutPanel oldRootPanel = parentGroup.Root.RootPanel as LayoutPanel;
  423. root.RootPanel = panel;
  424. panel.Children.Add(oldRootPanel);
  425. panel.Children.Add(previousContainer);
  426. }
  427. break;
  428. }
  429. }
  430. else
  431. {
  432. //I'm about to remove parentGroup, redirect any content (ie hidden contents) that point to it
  433. //to previousContainer
  434. LayoutRoot root = parentGroup.Root as LayoutRoot;
  435. foreach (var cnt in root.Descendents().OfType<ILayoutPreviousContainer>().Where(c => c.PreviousContainer == parentGroup))
  436. {
  437. cnt.PreviousContainer = previousContainer;
  438. }
  439. }
  440. foreach (var anchorableToToggle in parentGroup.Children.ToArray())
  441. {
  442. previousContainer.Children.Add(anchorableToToggle);
  443. }
  444. parentSide.Children.Remove(parentGroup);
  445. }
  446. #endregion
  447. #region Anchorable is docked
  448. else if (Parent is LayoutAnchorablePane)
  449. {
  450. var root = Root;
  451. var parentPane = Parent as LayoutAnchorablePane;
  452. var newAnchorGroup = new LayoutAnchorGroup();
  453. ((ILayoutPreviousContainer)newAnchorGroup).PreviousContainer = parentPane;
  454. foreach (var anchorableToImport in parentPane.Children.ToArray())
  455. newAnchorGroup.Children.Add(anchorableToImport);
  456. //detect anchor side for the pane
  457. var anchorSide = parentPane.GetSide();
  458. switch (anchorSide)
  459. {
  460. case AnchorSide.Right:
  461. root.RightSide.Children.Add(newAnchorGroup);
  462. break;
  463. case AnchorSide.Left:
  464. root.LeftSide.Children.Add(newAnchorGroup);
  465. break;
  466. case AnchorSide.Top:
  467. root.TopSide.Children.Add(newAnchorGroup);
  468. break;
  469. case AnchorSide.Bottom:
  470. root.BottomSide.Children.Add(newAnchorGroup);
  471. break;
  472. }
  473. }
  474. #endregion
  475. }
  476. #endregion
  477. #region CanHide
  478. private bool _canHide = true;
  479. public bool CanHide
  480. {
  481. get { return _canHide; }
  482. set
  483. {
  484. if (_canHide != value)
  485. {
  486. _canHide = value;
  487. RaisePropertyChanged("CanHide");
  488. }
  489. }
  490. }
  491. #endregion
  492. #region CanAutoHide
  493. private bool _canAutoHide = true;
  494. public bool CanAutoHide
  495. {
  496. get { return _canAutoHide; }
  497. set
  498. {
  499. if (_canAutoHide != value)
  500. {
  501. _canAutoHide = value;
  502. RaisePropertyChanged("CanAutoHide");
  503. }
  504. }
  505. }
  506. #endregion
  507. public override void ReadXml(System.Xml.XmlReader reader)
  508. {
  509. if (reader.MoveToAttribute("CanHide"))
  510. CanHide = bool.Parse(reader.Value);
  511. if (reader.MoveToAttribute("CanAutoHide"))
  512. CanAutoHide = bool.Parse(reader.Value);
  513. if (reader.MoveToAttribute("AutoHideWidth"))
  514. AutoHideWidth = double.Parse(reader.Value, CultureInfo.InvariantCulture);
  515. if (reader.MoveToAttribute("AutoHideHeight"))
  516. AutoHideHeight = double.Parse(reader.Value, CultureInfo.InvariantCulture);
  517. if (reader.MoveToAttribute("AutoHideMinWidth"))
  518. AutoHideMinWidth = double.Parse(reader.Value, CultureInfo.InvariantCulture);
  519. if (reader.MoveToAttribute("AutoHideMinHeight"))
  520. AutoHideMinHeight = double.Parse(reader.Value, CultureInfo.InvariantCulture);
  521. base.ReadXml(reader);
  522. }
  523. public override void WriteXml(System.Xml.XmlWriter writer)
  524. {
  525. if (!CanHide)
  526. writer.WriteAttributeString("CanHide", CanHide.ToString());
  527. if (!CanAutoHide)
  528. writer.WriteAttributeString("CanAutoHide", CanAutoHide.ToString(CultureInfo.InvariantCulture));
  529. if (AutoHideWidth > 0)
  530. writer.WriteAttributeString("AutoHideWidth", AutoHideWidth.ToString(CultureInfo.InvariantCulture));
  531. if (AutoHideHeight > 0)
  532. writer.WriteAttributeString("AutoHideHeight", AutoHideHeight.ToString(CultureInfo.InvariantCulture));
  533. if (AutoHideMinWidth != 25.0)
  534. writer.WriteAttributeString("AutoHideMinWidth", AutoHideMinWidth.ToString(CultureInfo.InvariantCulture));
  535. if (AutoHideMinHeight != 25.0)
  536. writer.WriteAttributeString("AutoHideMinHeight", AutoHideMinHeight.ToString(CultureInfo.InvariantCulture));
  537. base.WriteXml(writer);
  538. }
  539. public override void Close()
  540. {
  541. this.CloseAnchorable();
  542. }
  543. internal void CloseAnchorable()
  544. {
  545. if( this.TestCanClose() )
  546. {
  547. if( this.IsAutoHidden )
  548. this.ToggleAutoHide();
  549. this.CloseInternal();
  550. }
  551. }
  552. #if TRACE
  553. public override void ConsoleDump(int tab)
  554. {
  555. System.Diagnostics.Trace.Write( new string( ' ', tab * 4 ) );
  556. System.Diagnostics.Trace.WriteLine( "Anchorable()" );
  557. }
  558. #endif
  559. }
  560. }