PageRenderTime 52ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/MedLink2011/Controls/System.Windows.Controls.FloatableWindow.cs

#
C# | 1116 lines | 691 code | 156 blank | 269 comment | 158 complexity | c3073b2ecbe69737def0be6eff3a6650 MD5 | raw file
  1. // This source is subject to the Microsoft Public License (Ms-PL).
  2. // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
  3. using System.Windows.Input;
  4. using System.Windows.Media;
  5. using System.Windows.Media.Animation;
  6. using System.ComponentModel;
  7. using System.Diagnostics;
  8. using System.Windows.Controls.Primitives;
  9. using System.Collections.ObjectModel;
  10. using System.Linq;
  11. namespace System.Windows.Controls
  12. {
  13. [TemplatePart(Name = PART_Chrome, Type = typeof(FrameworkElement))]
  14. [TemplatePart(Name = PART_CloseButton, Type = typeof(ButtonBase))]
  15. [TemplatePart(Name = PART_ContentRoot, Type = typeof(FrameworkElement))]
  16. [TemplatePart(Name = PART_Root, Type = typeof(FrameworkElement))]
  17. [TemplatePart(Name = PART_Resizer, Type = typeof(FrameworkElement))]
  18. [TemplateVisualState(Name = VSMSTATE_StateClosing, GroupName = VSMGROUP_Window)]
  19. [TemplateVisualState(Name = VSMSTATE_StateOpen, GroupName = VSMGROUP_Window)]
  20. [TemplateVisualState(Name = VSMSTATE_StateOpening, GroupName = VSMGROUP_Window)]
  21. public class FloatableWindow : ContentControl
  22. {
  23. #region Static Fields and Constants
  24. /// <summary>
  25. /// The name of the Chrome template part.
  26. /// </summary>
  27. private const string PART_Chrome = "Chrome";
  28. /// <summary>
  29. /// The name of the Resizer template part.
  30. /// </summary>
  31. private const string PART_Resizer = "Resizer";
  32. /// <summary>
  33. /// The name of the CloseButton template part.
  34. /// </summary>
  35. private const string PART_CloseButton = "CloseButton";
  36. /// <summary>
  37. /// The name of the ContentRoot template part.
  38. /// </summary>
  39. private const string PART_ContentRoot = "ContentRoot";
  40. /// <summary>
  41. /// The name of the Overlay template part.
  42. /// </summary>
  43. private const string PART_Overlay = "Overlay";
  44. /// <summary>
  45. /// The name of the Root template part.
  46. /// </summary>
  47. private const string PART_Root = "Root";
  48. /// <summary>
  49. /// The name of the WindowStates VSM group.
  50. /// </summary>
  51. private const string VSMGROUP_Window = "WindowStates";
  52. /// <summary>
  53. /// The name of the Closing VSM state.
  54. /// </summary>
  55. private const string VSMSTATE_StateClosing = "Closing";
  56. /// <summary>
  57. /// The name of the Open VSM state.
  58. /// </summary>
  59. private const string VSMSTATE_StateOpen = "Open";
  60. /// <summary>
  61. /// The name of the Opening VSM state.
  62. /// </summary>
  63. private const string VSMSTATE_StateOpening = "Opening";
  64. /// <summary>
  65. /// Title of the ChildWindow.
  66. /// </summary>
  67. public static readonly DependencyProperty TitleProperty =
  68. DependencyProperty.Register(
  69. "Title",
  70. typeof(object),
  71. typeof(FloatableWindow),
  72. null);
  73. /// <summary>
  74. /// Gets the root visual element.
  75. /// </summary>
  76. private static Control RootVisual
  77. {
  78. get
  79. {
  80. return Application.Current == null ? null : (Application.Current.RootVisual as Control);
  81. }
  82. }
  83. #endregion Static Fields and Constants
  84. #region Member Fields
  85. /// <summary>
  86. /// Set in the overloaded Show method. Offsets the Popup vertically from the top left corner of the browser window by this amount.
  87. /// </summary>
  88. private double _verticalOffset;
  89. /// <summary>
  90. /// Set in the overloaded Show method. Offsets the Popup horizontally from the top left corner of the browser window by this amount.
  91. /// </summary>
  92. private double _horizontalOffset;
  93. /// <summary>
  94. /// Private accessor for the Chrome.
  95. /// </summary>
  96. private FrameworkElement _chrome;
  97. /// <summary>
  98. /// Private accessor for the Resizer.
  99. /// </summary>
  100. private FrameworkElement _resizer;
  101. /// <summary>
  102. /// Private accessor for the IsModal
  103. /// </summary>
  104. [DefaultValue(false)]
  105. private bool _modal;
  106. /// <summary>
  107. /// Private accessor for the click point on the chrome.
  108. /// </summary>
  109. private Point _clickPoint;
  110. /// <summary>
  111. /// Private accessor for the close button.
  112. /// </summary>
  113. private ButtonBase _closeButton;
  114. /// <summary>
  115. /// Private accessor for the Closing storyboard.
  116. /// </summary>
  117. private Storyboard _closed;
  118. /// <summary>
  119. /// Content area desired width.
  120. /// </summary>
  121. private double _desiredContentWidth;
  122. /// <summary>
  123. /// Content area desired height.
  124. /// </summary>
  125. private double _desiredContentHeight;
  126. /// <summary>
  127. /// Private accessor for the Dialog Result property.
  128. /// </summary>
  129. private bool? _dialogresult;
  130. /// <summary>
  131. /// Boolean value that specifies whether the window is in closing state or not.
  132. /// </summary>
  133. private bool _isClosing;
  134. /// <summary>
  135. /// Boolean value that specifies whether the application is exit or not.
  136. /// </summary>
  137. private bool _isAppExit;
  138. /// <summary>
  139. /// Boolean value that specifies whether the window is in opening state or not.
  140. /// </summary>
  141. private bool _isOpening;
  142. /// <summary>
  143. /// Private accessor for the Opening storyboard.
  144. /// </summary>
  145. private Storyboard _opened;
  146. /// <summary>
  147. /// Private accessor for the Overlay of the window.
  148. /// </summary>
  149. private FrameworkElement _overlay;
  150. /// <summary>
  151. /// Boolean value that specifies whether the mouse is captured or not.
  152. /// </summary>
  153. private bool _isMouseCaptured;
  154. /// <summary>
  155. /// Private accessor for the Root of the window.
  156. /// </summary>
  157. private FrameworkElement _root;
  158. private static int z;
  159. #endregion Member Fields
  160. #region Constructors
  161. /// <summary>
  162. /// Default constructor.
  163. /// </summary>
  164. public FloatableWindow()
  165. {
  166. this.DefaultStyleKey = typeof(FloatableWindow);
  167. this.ResizeMode = ResizeMode.CanResize;
  168. }
  169. #endregion Constructors
  170. #region Events
  171. /// <summary>
  172. /// Occurs when the window is closed.
  173. /// </summary>
  174. public event EventHandler Closed;
  175. /// <summary>
  176. /// Occurs directly after Close is called, and can be handled to cancel window closure.
  177. /// </summary>
  178. public event EventHandler<CancelEventArgs> Closing;
  179. #endregion Events
  180. #region Properties
  181. /// <summary>
  182. /// Gets the internal accessor for the ContentRoot of the window.
  183. /// </summary>
  184. internal FrameworkElement ContentRoot
  185. {
  186. get;
  187. private set;
  188. }
  189. /// <summary>
  190. /// Setting for the horizontal positioning offset for start position
  191. /// </summary>
  192. public double HorizontalOffset
  193. {
  194. get { return _horizontalOffset; }
  195. set { _horizontalOffset = value; }
  196. }
  197. /// <summary>
  198. /// Setting for the vertical positioning offset for start position
  199. /// </summary>
  200. public double VerticalOffset
  201. {
  202. get { return _verticalOffset; }
  203. set { _verticalOffset = value; }
  204. }
  205. /// <summary>
  206. /// Gets the internal accessor for the modal of the window.
  207. /// </summary>
  208. public bool IsModal
  209. {
  210. get
  211. {
  212. return _modal;
  213. }
  214. }
  215. /// <summary>
  216. /// Gets or sets the DialogResult property.
  217. /// </summary>
  218. public bool? DialogResult
  219. {
  220. get
  221. {
  222. return this._dialogresult;
  223. }
  224. set
  225. {
  226. if (this._dialogresult != value)
  227. {
  228. this._dialogresult = value;
  229. this.Close();
  230. }
  231. }
  232. }
  233. /// <summary>
  234. /// Gets the internal accessor for the PopUp of the window.
  235. /// </summary>
  236. internal Popup ChildWindowPopup
  237. {
  238. get;
  239. private set;
  240. }
  241. /// <summary>
  242. /// Gets or sets the Title property.
  243. /// </summary>
  244. public object Title
  245. {
  246. get { return (object)GetValue(TitleProperty); }
  247. set { SetValue(TitleProperty, value); }
  248. }
  249. /// <summary>
  250. /// Gets a value indicating whether the PopUp is open or not.
  251. /// </summary>
  252. private bool IsOpen
  253. {
  254. get
  255. {
  256. return (this.ChildWindowPopup != null && this.ChildWindowPopup.IsOpen);
  257. }
  258. }
  259. public ResizeMode ResizeMode
  260. {
  261. get;
  262. set;
  263. }
  264. #endregion Properties
  265. #region Static Methods
  266. /// <summary>
  267. /// Inverts the input matrix.
  268. /// </summary>
  269. /// <param name="matrix">The matrix values that is to be inverted.</param>
  270. /// <returns>Returns a value indicating whether the inversion was successful or not.</returns>
  271. private static bool InvertMatrix(ref Matrix matrix)
  272. {
  273. double determinant = (matrix.M11 * matrix.M22) - (matrix.M12 * matrix.M21);
  274. if (determinant == 0.0)
  275. {
  276. return false;
  277. }
  278. Matrix matCopy = matrix;
  279. matrix.M11 = matCopy.M22 / determinant;
  280. matrix.M12 = -1 * matCopy.M12 / determinant;
  281. matrix.M21 = -1 * matCopy.M21 / determinant;
  282. matrix.M22 = matCopy.M11 / determinant;
  283. matrix.OffsetX = ((matCopy.OffsetY * matCopy.M21) - (matCopy.OffsetX * matCopy.M22)) / determinant;
  284. matrix.OffsetY = ((matCopy.OffsetX * matCopy.M12) - (matCopy.OffsetY * matCopy.M11)) / determinant;
  285. return true;
  286. }
  287. #endregion Static Methods
  288. #region Methods
  289. /// <summary>
  290. /// Executed when the application is exited.
  291. /// </summary>
  292. /// <param name="sender">The sender.</param>
  293. /// <param name="e">Event args.</param>
  294. internal void Application_Exit(object sender, EventArgs e)
  295. {
  296. if (this.IsOpen)
  297. {
  298. this._isAppExit = true;
  299. try
  300. {
  301. this.Close();
  302. }
  303. finally
  304. {
  305. this._isAppExit = false;
  306. }
  307. }
  308. }
  309. /// <summary>
  310. /// Executed when focus is given to the window via a click. Attempts to bring current
  311. /// window to the front in the event there are more windows.
  312. /// </summary>
  313. internal void BringToFront()
  314. {
  315. z++;
  316. Canvas.SetZIndex(this, z);
  317. #if DEBUG
  318. this.Title = z.ToString();
  319. #endif
  320. }
  321. /// <summary>
  322. /// Changes the visual state of the ChildWindow.
  323. /// </summary>
  324. private void ChangeVisualState()
  325. {
  326. if (this._isClosing)
  327. {
  328. VisualStateManager.GoToState(this, VSMSTATE_StateClosing, false);
  329. }
  330. else
  331. {
  332. if (this._isOpening)
  333. {
  334. VisualStateManager.GoToState(this, VSMSTATE_StateOpening, false);
  335. }
  336. else
  337. {
  338. VisualStateManager.GoToState(this, VSMSTATE_StateOpen, false);
  339. BringToFront();
  340. }
  341. }
  342. }
  343. /// <summary>
  344. /// Executed when ChildWindow size is changed.
  345. /// </summary>
  346. /// <param name="sender">Sender object.</param>
  347. /// <param name="e">Size changed event args.</param>
  348. private void ChildWindow_SizeChanged(object sender, SizeChangedEventArgs e)
  349. {
  350. if (_modal)
  351. {
  352. if (this._overlay != null)
  353. {
  354. if (e.NewSize.Height != this._overlay.Height)
  355. {
  356. this._desiredContentHeight = e.NewSize.Height;
  357. }
  358. if (e.NewSize.Width != this._overlay.Width)
  359. {
  360. this._desiredContentWidth = e.NewSize.Width;
  361. }
  362. }
  363. if (this.IsOpen)
  364. {
  365. this.UpdateOverlaySize();
  366. }
  367. }
  368. }
  369. /// <summary>
  370. /// Closes a Window.
  371. /// </summary>
  372. public void Close()
  373. {
  374. CancelEventArgs e = new CancelEventArgs();
  375. this.OnClosing(e);
  376. // On ApplicationExit, close() cannot be cancelled
  377. if (!e.Cancel || this._isAppExit)
  378. {
  379. if (RootVisual != null && _modal)
  380. {
  381. RootVisual.IsEnabled = true;
  382. }
  383. // Close Popup
  384. if (this.IsOpen)
  385. {
  386. if (this._closed != null)
  387. {
  388. // Popup will be closed when the storyboard ends
  389. this._isClosing = true;
  390. try
  391. {
  392. this.ChangeVisualState();
  393. }
  394. finally
  395. {
  396. this._isClosing = false;
  397. }
  398. }
  399. else
  400. {
  401. // If no closing storyboard is defined, close the Popup
  402. this.ChildWindowPopup.IsOpen = false;
  403. }
  404. if (!this._dialogresult.HasValue)
  405. {
  406. // If close action is not happening because of DialogResult property change action,
  407. // Dialogresult is always false:
  408. this._dialogresult = false;
  409. }
  410. this.OnClosed(EventArgs.Empty);
  411. this.UnSubscribeFromEvents();
  412. this.UnsubscribeFromTemplatePartEvents();
  413. //TODO: See if this matters for FloatableWindow
  414. if (Application.Current.RootVisual != null)
  415. {
  416. Application.Current.RootVisual.GotFocus -= new RoutedEventHandler(this.RootVisual_GotFocus);
  417. }
  418. }
  419. }
  420. else
  421. {
  422. // If the Close is cancelled, DialogResult should always be NULL:
  423. this._dialogresult = null;
  424. }
  425. }
  426. /// <summary>
  427. /// Brings the window to the front of others
  428. /// </summary>
  429. /// <param name="sender"></param>
  430. /// <param name="e"></param>
  431. internal void ContentRoot_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
  432. {
  433. BringToFront();
  434. }
  435. /// <summary>
  436. /// Executed when the CloseButton is clicked.
  437. /// </summary>
  438. /// <param name="sender">Sender object.</param>
  439. /// <param name="e">Routed event args.</param>
  440. internal void CloseButton_Click(object sender, RoutedEventArgs e)
  441. {
  442. this.Close();
  443. }
  444. /// <summary>
  445. /// Executed when the Closing storyboard ends.
  446. /// </summary>
  447. /// <param name="sender">Sender object.</param>
  448. /// <param name="e">Event args.</param>
  449. private void Closing_Completed(object sender, EventArgs e)
  450. {
  451. if (this.ChildWindowPopup != null)
  452. {
  453. this.ChildWindowPopup.IsOpen = false;
  454. }
  455. if (this._closed != null)
  456. {
  457. this._closed.Completed -= new EventHandler(this.Closing_Completed);
  458. }
  459. }
  460. /// <summary>
  461. /// Executed when the a key is presses when the window is open.
  462. /// </summary>
  463. /// <param name="sender">Sender object.</param>
  464. /// <param name="e">Key event args.</param>
  465. private void ChildWindow_KeyDown(object sender, KeyEventArgs e)
  466. {
  467. FloatableWindow ew = sender as FloatableWindow;
  468. Debug.Assert(ew != null, "FloatableWindow instance is null.");
  469. // Ctrl+Shift+F4 closes the FloatableWindow
  470. if (e != null && !e.Handled && e.Key == Key.F4 &&
  471. ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control) &&
  472. ((Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift))
  473. {
  474. ew.Close();
  475. e.Handled = true;
  476. }
  477. }
  478. /// <summary>
  479. /// Executed when the window loses focus.
  480. /// </summary>
  481. /// <param name="sender">Sender object.</param>
  482. /// <param name="e">Routed event args.</param>
  483. private void ChildWindow_LostFocus(object sender, RoutedEventArgs e)
  484. {
  485. // If the ChildWindow loses focus but the popup is still open,
  486. // it means another popup is opened. To get the focus back when the
  487. // popup is closed, we handle GotFocus on the RootVisual
  488. // TODO: Something else could get focus and handle the GotFocus event right.
  489. // Try listening to routed events that were Handled (new SL 3 feature)
  490. //TODO: See if this matters for FloatableWindow
  491. if (this.IsOpen && Application.Current != null && Application.Current.RootVisual != null)
  492. {
  493. Application.Current.RootVisual.GotFocus += new RoutedEventHandler(this.RootVisual_GotFocus);
  494. }
  495. }
  496. /// <summary>
  497. /// Executed when mouse left button is down on the chrome.
  498. /// </summary>
  499. /// <param name="sender">Sender object.</param>
  500. /// <param name="e">Mouse button event args.</param>
  501. private void Chrome_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
  502. {
  503. if (this._chrome != null)
  504. {
  505. this._chrome.CaptureMouse();
  506. this._isMouseCaptured = true;
  507. this._clickPoint = e.GetPosition(sender as UIElement);
  508. }
  509. }
  510. /// <summary>
  511. /// Executed when mouse left button is up on the chrome.
  512. /// </summary>
  513. /// <param name="sender">Sender object.</param>
  514. /// <param name="e">Mouse button event args.</param>
  515. private void Chrome_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
  516. {
  517. if (this._chrome != null)
  518. {
  519. this._chrome.ReleaseMouseCapture();
  520. this._isMouseCaptured = false;
  521. }
  522. }
  523. /// <summary>
  524. /// Executed when mouse moves on the chrome.
  525. /// </summary>
  526. /// <param name="sender">Sender object.</param>
  527. /// <param name="e">Mouse event args.</param>
  528. private void Chrome_MouseMove(object sender, MouseEventArgs e)
  529. {
  530. if (this._isMouseCaptured && this.ContentRoot != null)
  531. {
  532. // If the child window is dragged out of the page, return
  533. if (Application.Current != null && Application.Current.RootVisual != null &&
  534. (e.GetPosition(Application.Current.RootVisual).X < 0 || e.GetPosition(Application.Current.RootVisual).Y < 0))
  535. {
  536. return;
  537. }
  538. TransformGroup transformGroup = this.ContentRoot.RenderTransform as TransformGroup;
  539. if (transformGroup == null)
  540. {
  541. transformGroup = new TransformGroup();
  542. transformGroup.Children.Add(this.ContentRoot.RenderTransform);
  543. }
  544. TranslateTransform t = new TranslateTransform();
  545. t.X = e.GetPosition(this.ContentRoot).X - this._clickPoint.X;
  546. t.Y = e.GetPosition(this.ContentRoot).Y - this._clickPoint.Y;
  547. if (transformGroup != null)
  548. {
  549. transformGroup.Children.Add(t);
  550. this.ContentRoot.RenderTransform = transformGroup;
  551. }
  552. }
  553. }
  554. /// <summary>
  555. /// When the template is applied, this loads all the template parts.
  556. /// </summary>
  557. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "No need to split the code into two parts.")]
  558. public override void OnApplyTemplate()
  559. {
  560. this.UnsubscribeFromTemplatePartEvents();
  561. base.OnApplyTemplate();
  562. this._closeButton = GetTemplateChild(PART_CloseButton) as ButtonBase;
  563. if (this._closed != null)
  564. {
  565. this._closed.Completed -= new EventHandler(this.Closing_Completed);
  566. }
  567. if (this._opened != null)
  568. {
  569. this._opened.Completed -= new EventHandler(this.Opening_Completed);
  570. }
  571. this._root = GetTemplateChild(PART_Root) as FrameworkElement;
  572. this._resizer = GetTemplateChild(PART_Resizer) as FrameworkElement;
  573. if (this._root != null)
  574. {
  575. Collection<VisualStateGroup> groups = VisualStateManager.GetVisualStateGroups(this._root) as Collection<VisualStateGroup>;
  576. if (groups != null)
  577. {
  578. System.Collections.IList states = (from stategroup in groups
  579. where stategroup.Name == FloatableWindow.VSMGROUP_Window
  580. select stategroup.States).FirstOrDefault();
  581. Collection<VisualState> statesCol = states as Collection<VisualState>;
  582. if (statesCol != null)
  583. {
  584. this._closed = (from state in statesCol
  585. where state.Name == FloatableWindow.VSMSTATE_StateClosing
  586. select state.Storyboard).FirstOrDefault();
  587. this._opened = (from state in statesCol
  588. where state.Name == FloatableWindow.VSMSTATE_StateOpening
  589. select state.Storyboard).FirstOrDefault();
  590. }
  591. }
  592. //TODO: Figure out why I can't wire up the event below in SubscribeToTemplatePartEvents
  593. this._root.MouseLeftButtonDown += new MouseButtonEventHandler(this.ContentRoot_MouseLeftButtonDown);
  594. if (this.ResizeMode == ResizeMode.CanResize)
  595. {
  596. this._resizer.MouseLeftButtonDown += new System.Windows.Input.MouseButtonEventHandler(Resizer_MouseLeftButtonDown);
  597. this._resizer.MouseLeftButtonUp += new System.Windows.Input.MouseButtonEventHandler(Resizer_MouseLeftButtonUp);
  598. this._resizer.MouseMove += new System.Windows.Input.MouseEventHandler(Resizer_MouseMove);
  599. this._resizer.MouseEnter += new MouseEventHandler(Resizer_MouseEnter);
  600. this._resizer.MouseLeave += new MouseEventHandler(Resizer_MouseLeave);
  601. }
  602. else
  603. {
  604. this._resizer.Opacity = 0;
  605. }
  606. }
  607. this.ContentRoot = GetTemplateChild(PART_ContentRoot) as FrameworkElement;
  608. this._chrome = GetTemplateChild(PART_Chrome) as FrameworkElement;
  609. this._overlay = GetTemplateChild(PART_Overlay) as FrameworkElement;
  610. this.SubscribeToTemplatePartEvents();
  611. this.SubscribeToStoryBoardEvents();
  612. // Update overlay size
  613. if (this.IsOpen)
  614. {
  615. this._desiredContentHeight = this.Height;
  616. this._desiredContentWidth = this.Width;
  617. this.UpdateOverlaySize();
  618. this.UpdateRenderTransform();
  619. this._isOpening = true;
  620. try
  621. {
  622. this.ChangeVisualState();
  623. }
  624. finally
  625. {
  626. this._isOpening = false;
  627. }
  628. }
  629. }
  630. void Resizer_MouseLeave(object sender, MouseEventArgs e)
  631. {
  632. if (!this._isMouseCaptured)
  633. {
  634. this._resizer.Opacity = .25;
  635. }
  636. }
  637. void Resizer_MouseEnter(object sender, MouseEventArgs e)
  638. {
  639. if (!this._isMouseCaptured)
  640. {
  641. this._resizer.Opacity = 1;
  642. }
  643. }
  644. /// <summary>
  645. /// Raises the Closed event.
  646. /// </summary>
  647. /// <param name="e">An EventArgs that contains the event data.</param>
  648. protected virtual void OnClosed(EventArgs e)
  649. {
  650. EventHandler handler = this.Closed;
  651. if (null != handler)
  652. {
  653. handler(this, e);
  654. }
  655. }
  656. /// <summary>
  657. /// Raises the Closing event.
  658. /// </summary>
  659. /// <param name="e">A CancelEventArgs that contains the event data.</param>
  660. protected virtual void OnClosing(CancelEventArgs e)
  661. {
  662. EventHandler<CancelEventArgs> handler = this.Closing;
  663. if (null != handler)
  664. {
  665. handler(this, e);
  666. }
  667. }
  668. /// <summary>
  669. /// Executed when the opening storyboard finishes.
  670. /// </summary>
  671. /// <param name="sender">Sender object.</param>
  672. /// <param name="e">Event args.</param>
  673. private void Opening_Completed(object sender, EventArgs e)
  674. {
  675. this.ChangeVisualState();
  676. this.Focus();
  677. if (this._opened != null)
  678. {
  679. this._opened.Completed -= new EventHandler(this.Opening_Completed);
  680. }
  681. }
  682. /// <summary>
  683. /// Executed when the page resizes.
  684. /// </summary>
  685. /// <param name="sender">Sender object.</param>
  686. /// <param name="e">Event args.</param>
  687. private void Page_Resized(object sender, EventArgs e)
  688. {
  689. if (this.ChildWindowPopup != null)
  690. {
  691. this.UpdateOverlaySize();
  692. }
  693. }
  694. /// <summary>
  695. /// Executed when the root visual gets focus.
  696. /// </summary>
  697. /// <param name="sender">Sender object.</param>
  698. /// <param name="e">Routed event args.</param>
  699. private void RootVisual_GotFocus(object sender, RoutedEventArgs e)
  700. {
  701. this.Focus();
  702. }
  703. /// <summary>
  704. /// Opens a child window. The interaction with the underlying UI is disabled but it is not a
  705. /// blocking call.
  706. /// </summary>
  707. public void Show()
  708. {
  709. ShowWindow(false);
  710. }
  711. public void Show(double horizontalOffset, double verticalOffset)
  712. {
  713. _horizontalOffset = horizontalOffset;
  714. _verticalOffset = verticalOffset;
  715. ShowWindow(false);
  716. }
  717. internal void ShowWindow(bool isModal)
  718. {
  719. _modal = isModal;
  720. this.SubscribeToEvents();
  721. this.SubscribeToTemplatePartEvents();
  722. this.SubscribeToStoryBoardEvents();
  723. if (this.ChildWindowPopup == null)
  724. {
  725. this.ChildWindowPopup = new Popup();
  726. this.ChildWindowPopup.Child = this;
  727. }
  728. // Margin, MaxHeight and MinHeight properties should not be overwritten:
  729. this.Margin = new Thickness(0);
  730. this.MaxHeight = double.PositiveInfinity;
  731. this.MaxWidth = double.PositiveInfinity;
  732. if (this.ChildWindowPopup != null && Application.Current.RootVisual != null)
  733. {
  734. this.ChildWindowPopup.IsOpen = true;
  735. this.ChildWindowPopup.HorizontalOffset = _horizontalOffset;
  736. this.ChildWindowPopup.VerticalOffset = _verticalOffset;
  737. // while the ChildWindow is open, the DialogResult is always NULL:
  738. this._dialogresult = null;
  739. }
  740. //disable the underlying UI
  741. if (RootVisual != null && _modal)
  742. {
  743. RootVisual.IsEnabled = false;
  744. }
  745. // if the template is already loaded, display loading visuals animation
  746. if (this.ContentRoot != null)
  747. {
  748. this._isOpening = true;
  749. try
  750. {
  751. this.ChangeVisualState();
  752. }
  753. finally
  754. {
  755. this._isOpening = false;
  756. }
  757. }
  758. }
  759. public void ShowDialog()
  760. {
  761. ShowWindow(true);
  762. }
  763. /// <summary>
  764. /// Subscribes to events when the ChildWindow is opened.
  765. /// </summary>
  766. private void SubscribeToEvents()
  767. {
  768. if (Application.Current != null && Application.Current.Host != null && Application.Current.Host.Content != null)
  769. {
  770. Application.Current.Exit += new EventHandler(this.Application_Exit);
  771. Application.Current.Host.Content.Resized += new EventHandler(this.Page_Resized);
  772. }
  773. this.KeyDown += new KeyEventHandler(this.ChildWindow_KeyDown);
  774. if (_modal)
  775. {
  776. this.LostFocus += new RoutedEventHandler(this.ChildWindow_LostFocus);
  777. }
  778. this.SizeChanged += new SizeChangedEventHandler(this.ChildWindow_SizeChanged);
  779. }
  780. /// <summary>
  781. /// Subscribes to events that are on the storyboards.
  782. /// Unsubscribing from these events happen in the event handlers individually.
  783. /// </summary>
  784. private void SubscribeToStoryBoardEvents()
  785. {
  786. if (this._closed != null)
  787. {
  788. this._closed.Completed += new EventHandler(this.Closing_Completed);
  789. }
  790. if (this._opened != null)
  791. {
  792. this._opened.Completed += new EventHandler(this.Opening_Completed);
  793. }
  794. }
  795. /// <summary>
  796. /// Subscribes to events on the template parts.
  797. /// </summary>
  798. private void SubscribeToTemplatePartEvents()
  799. {
  800. if (this._closeButton != null)
  801. {
  802. this._closeButton.Click += new RoutedEventHandler(this.CloseButton_Click);
  803. }
  804. if (this._chrome != null)
  805. {
  806. this._chrome.MouseLeftButtonDown += new MouseButtonEventHandler(this.Chrome_MouseLeftButtonDown);
  807. this._chrome.MouseLeftButtonUp += new MouseButtonEventHandler(this.Chrome_MouseLeftButtonUp);
  808. this._chrome.MouseMove += new MouseEventHandler(this.Chrome_MouseMove);
  809. }
  810. }
  811. /// <summary>
  812. /// Unsubscribe from events when the ChildWindow is closed.
  813. /// </summary>
  814. private void UnSubscribeFromEvents()
  815. {
  816. if (Application.Current != null && Application.Current.Host != null && Application.Current.Host.Content != null)
  817. {
  818. Application.Current.Exit -= new EventHandler(this.Application_Exit);
  819. Application.Current.Host.Content.Resized -= new EventHandler(this.Page_Resized);
  820. }
  821. this.KeyDown -= new KeyEventHandler(this.ChildWindow_KeyDown);
  822. if (_modal)
  823. {
  824. this.LostFocus -= new RoutedEventHandler(this.ChildWindow_LostFocus);
  825. }
  826. this.SizeChanged -= new SizeChangedEventHandler(this.ChildWindow_SizeChanged);
  827. }
  828. /// <summary>
  829. /// Unsubscribe from the events that are subscribed on the template part elements.
  830. /// </summary>
  831. private void UnsubscribeFromTemplatePartEvents()
  832. {
  833. if (this._closeButton != null)
  834. {
  835. this._closeButton.Click -= new RoutedEventHandler(this.CloseButton_Click);
  836. }
  837. if (this._chrome != null)
  838. {
  839. this._chrome.MouseLeftButtonDown -= new MouseButtonEventHandler(this.Chrome_MouseLeftButtonDown);
  840. this._chrome.MouseLeftButtonUp -= new MouseButtonEventHandler(this.Chrome_MouseLeftButtonUp);
  841. this._chrome.MouseMove -= new MouseEventHandler(this.Chrome_MouseMove);
  842. }
  843. }
  844. /// <summary>
  845. /// Updates the size of the overlay of the window.
  846. /// </summary>
  847. private void UpdateOverlaySize()
  848. {
  849. if (_modal)
  850. {
  851. if (this._overlay != null && Application.Current != null && Application.Current.Host != null && Application.Current.Host.Content != null)
  852. {
  853. this._overlay.Visibility = Visibility.Visible;
  854. this.Height = Application.Current.Host.Content.ActualHeight;
  855. this.Width = Application.Current.Host.Content.ActualWidth;
  856. this._overlay.Height = this.Height;
  857. this._overlay.Width = this.Width;
  858. if (this.ContentRoot != null)
  859. {
  860. this.ContentRoot.Width = this._desiredContentWidth;
  861. this.ContentRoot.Height = this._desiredContentHeight;
  862. }
  863. }
  864. }
  865. else
  866. {
  867. if (this._overlay != null)
  868. {
  869. this._overlay.Visibility = Visibility.Collapsed;
  870. }
  871. }
  872. }
  873. /// <summary>
  874. /// Updates the render transform applied on the overlay.
  875. /// </summary>
  876. private void UpdateRenderTransform()
  877. {
  878. if (this._root != null && this.ContentRoot != null)
  879. {
  880. // The _overlay part should not be affected by the render transform applied on the
  881. // ChildWindow. In order to achieve this, we adjust an identity matrix to represent
  882. // the _root's transformation, invert it, apply the inverted matrix on the _root, so that
  883. // nothing is affected by the rendertransform, and apply the original transform only on the Content
  884. GeneralTransform gt = this._root.TransformToVisual(null);
  885. if (gt != null)
  886. {
  887. Point p10 = new Point(1, 0);
  888. Point p01 = new Point(0, 1);
  889. Point transform10 = gt.Transform(p10);
  890. Point transform01 = gt.Transform(p01);
  891. Matrix transformToRootMatrix = Matrix.Identity;
  892. transformToRootMatrix.M11 = transform10.X;
  893. transformToRootMatrix.M12 = transform10.Y;
  894. transformToRootMatrix.M21 = transform01.X;
  895. transformToRootMatrix.M22 = transform01.Y;
  896. MatrixTransform original = new MatrixTransform();
  897. original.Matrix = transformToRootMatrix;
  898. InvertMatrix(ref transformToRootMatrix);
  899. MatrixTransform mt = new MatrixTransform();
  900. mt.Matrix = transformToRootMatrix;
  901. TransformGroup tg = this._root.RenderTransform as TransformGroup;
  902. if (tg != null)
  903. {
  904. tg.Children.Add(mt);
  905. }
  906. else
  907. {
  908. this._root.RenderTransform = mt;
  909. }
  910. tg = this.ContentRoot.RenderTransform as TransformGroup;
  911. if (tg != null)
  912. {
  913. tg.Children.Add(original);
  914. }
  915. else
  916. {
  917. this.ContentRoot.RenderTransform = original;
  918. }
  919. }
  920. }
  921. }
  922. private void Resizer_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
  923. {
  924. this._resizer.CaptureMouse();
  925. this._isMouseCaptured = true;
  926. this._clickPoint = e.GetPosition(sender as UIElement);
  927. #if DEBUG
  928. this.Title = string.Format("X:{0},Y:{1}", this._clickPoint.X.ToString(), this._clickPoint.Y.ToString());
  929. #endif
  930. }
  931. private void Resizer_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
  932. {
  933. this._resizer.ReleaseMouseCapture();
  934. this._isMouseCaptured = false;
  935. this._resizer.Opacity = 0.25;
  936. }
  937. private void Resizer_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
  938. {
  939. if (this._isMouseCaptured && this.ContentRoot != null)
  940. {
  941. // If the child window is dragged out of the page, return
  942. if (Application.Current != null && Application.Current.RootVisual != null &&
  943. (e.GetPosition(Application.Current.RootVisual).X < 0 || e.GetPosition(Application.Current.RootVisual).Y < 0))
  944. {
  945. return;
  946. }
  947. #if DEBUG
  948. this.Title = string.Format("X:{0},Y:{1}", this._clickPoint.X.ToString(), this._clickPoint.Y.ToString());
  949. #endif
  950. Point p = e.GetPosition(this.ContentRoot);
  951. if ((p.X > this._clickPoint.X) && (p.Y > this._clickPoint.Y))
  952. {
  953. this.Width = (double)(p.X - (12 - this._clickPoint.X));
  954. this.Height = (double)(p.Y - (12 - this._clickPoint.Y));
  955. }
  956. }
  957. }
  958. #endregion Methods
  959. }
  960. }