comparison SilverlightGlimpse/FloatableWindow/FloatableWindow.cs @ 62:810116cd6b8e

ErrorWindow working
author Steven Hollidge <stevenhollidge@hotmail.com>
date Sun, 22 Apr 2012 09:01:20 +0100
parents
children a0bcd783e612
comparison
equal deleted inserted replaced
61:9de81c9ad319 62:810116cd6b8e
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 // All other rights reserved.
4
5 using System.Collections;
6 using System.ComponentModel;
7 using System.Diagnostics;
8 using System.Windows.Automation;
9 using System.Windows.Automation.Peers;
10 using System.Windows.Controls.Primitives;
11 using System.Windows.Input;
12 using System.Windows.Media;
13 using System.Windows.Media.Animation;
14
15 namespace System.Windows.Controls
16 {
17 /// <summary>
18 /// Provides a window that can be displayed over a parent window and blocks
19 /// interaction with the parent window.
20 /// </summary>
21 /// <QualityBand>Preview</QualityBand>
22 [TemplatePart(Name = PART_Chrome, Type = typeof(FrameworkElement))]
23 [TemplatePart(Name = PART_CloseButton, Type = typeof(ButtonBase))]
24 [TemplatePart(Name = PART_ContentPresenter, Type = typeof(FrameworkElement))]
25 [TemplatePart(Name = PART_ContentRoot, Type = typeof(FrameworkElement))]
26 [TemplatePart(Name = PART_Overlay, Type = typeof(Panel))]
27 [TemplatePart(Name = PART_Root, Type = typeof(FrameworkElement))]
28 [TemplatePart(Name = PART_Resizer, Type = typeof(FrameworkElement))]
29 [TemplateVisualState(Name = VSMSTATE_StateClosed, GroupName = VSMGROUP_Window)]
30 [TemplateVisualState(Name = VSMSTATE_StateOpen, GroupName = VSMGROUP_Window)]
31 public class FloatableWindow : ContentControl
32 {
33 #region Static Fields and Constants
34
35 /// <summary>
36 /// The name of the Chrome template part.
37 /// </summary>
38 private const string PART_Chrome = "Chrome";
39
40 /// <summary>
41 /// The name of the Resizer template part.
42 /// </summary>
43 private const string PART_Resizer = "Resizer";
44
45 /// <summary>
46 /// The name of the CloseButton template part.
47 /// </summary>
48 private const string PART_CloseButton = "CloseButton";
49
50 /// <summary>
51 /// The name of the ContentPresenter template part.
52 /// </summary>
53 private const string PART_ContentPresenter = "ContentPresenter";
54
55 /// <summary>
56 /// The name of the ContentRoot template part.
57 /// </summary>
58 private const string PART_ContentRoot = "ContentRoot";
59
60 /// <summary>
61 /// The name of the Overlay template part.
62 /// </summary>
63 private const string PART_Overlay = "Overlay";
64
65 /// <summary>
66 /// The name of the Root template part.
67 /// </summary>
68 private const string PART_Root = "Root";
69
70 /// <summary>
71 /// The name of the WindowStates VSM group.
72 /// </summary>
73 private const string VSMGROUP_Window = "WindowStates";
74
75 /// <summary>
76 /// The name of the Closing VSM state.
77 /// </summary>
78 private const string VSMSTATE_StateClosed = "Closed";
79
80 /// <summary>
81 /// The name of the Opening VSM state.
82 /// </summary>
83 private const string VSMSTATE_StateOpen = "Open";
84
85 #region public bool HasCloseButton
86
87 /// <summary>
88 /// Gets or sets a value indicating whether the
89 /// <see cref="T:System.Windows.Controls.FloatableWindow" /> has a close
90 /// button.
91 /// </summary>
92 /// <value>
93 /// True if the child window has a close button; otherwise, false. The
94 /// default is true.
95 /// </value>
96 public bool HasCloseButton
97 {
98 get { return (bool)GetValue(HasCloseButtonProperty); }
99 set { SetValue(HasCloseButtonProperty, value); }
100 }
101
102 /// <summary>
103 /// Identifies the
104 /// <see cref="P:System.Windows.Controls.FloatableWindow.HasCloseButton" />
105 /// dependency property.
106 /// </summary>
107 /// <value>
108 /// The identifier for the
109 /// <see cref="P:System.Windows.Controls.FloatableWindow.HasCloseButton" />
110 /// dependency property.
111 /// </value>
112 public static readonly DependencyProperty HasCloseButtonProperty =
113 DependencyProperty.Register(
114 "HasCloseButton",
115 typeof(bool),
116 typeof(FloatableWindow),
117 new PropertyMetadata(true, OnHasCloseButtonPropertyChanged));
118
119 /// <summary>
120 /// HasCloseButtonProperty PropertyChangedCallback call back static function.
121 /// </summary>
122 /// <param name="d">FloatableWindow object whose HasCloseButton property is changed.</param>
123 /// <param name="e">DependencyPropertyChangedEventArgs which contains the old and new values.</param>
124 private static void OnHasCloseButtonPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
125 {
126 FloatableWindow cw = (FloatableWindow)d;
127
128 if (cw.CloseButton != null)
129 {
130 if ((bool)e.NewValue)
131 {
132 cw.CloseButton.Visibility = Visibility.Visible;
133 }
134 else
135 {
136 cw.CloseButton.Visibility = Visibility.Collapsed;
137 }
138 }
139 }
140
141 #endregion public bool HasCloseButton
142
143 #region public Brush OverlayBrush
144
145 /// <summary>
146 /// Gets or sets the visual brush that is used to cover the parent
147 /// window when the child window is open.
148 /// </summary>
149 /// <value>
150 /// The visual brush that is used to cover the parent window when the
151 /// <see cref="T:System.Windows.Controls.FloatableWindow" /> is open. The
152 /// default is null.
153 /// </value>
154 public Brush OverlayBrush
155 {
156 get { return (Brush)GetValue(OverlayBrushProperty); }
157 set { SetValue(OverlayBrushProperty, value); }
158 }
159
160 /// <summary>
161 /// Identifies the
162 /// <see cref="P:System.Windows.Controls.FloatableWindow.OverlayBrush" />
163 /// dependency property.
164 /// </summary>
165 /// <value>
166 /// The identifier for the
167 /// <see cref="P:System.Windows.Controls.FloatableWindow.OverlayBrush" />
168 /// dependency property.
169 /// </value>
170 public static readonly DependencyProperty OverlayBrushProperty =
171 DependencyProperty.Register(
172 "OverlayBrush",
173 typeof(Brush),
174 typeof(FloatableWindow),
175 new PropertyMetadata(OnOverlayBrushPropertyChanged));
176
177 /// <summary>
178 /// OverlayBrushProperty PropertyChangedCallback call back static function.
179 /// </summary>
180 /// <param name="d">FloatableWindow object whose OverlayBrush property is changed.</param>
181 /// <param name="e">DependencyPropertyChangedEventArgs which contains the old and new values.</param>
182 private static void OnOverlayBrushPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
183 {
184 FloatableWindow cw = (FloatableWindow)d;
185
186 if (cw.Overlay != null)
187 {
188 cw.Overlay.Background = (Brush)e.NewValue;
189 }
190 }
191
192 #endregion public Brush OverlayBrush
193
194 #region public double OverlayOpacity
195
196 /// <summary>
197 /// Gets or sets the opacity of the overlay brush that is used to cover
198 /// the parent window when the child window is open.
199 /// </summary>
200 /// <value>
201 /// The opacity of the overlay brush that is used to cover the parent
202 /// window when the <see cref="T:System.Windows.Controls.FloatableWindow" />
203 /// is open. The default is 1.0.
204 /// </value>
205 public double OverlayOpacity
206 {
207 get { return (double)GetValue(OverlayOpacityProperty); }
208 set { SetValue(OverlayOpacityProperty, value); }
209 }
210
211 /// <summary>
212 /// Identifies the
213 /// <see cref="P:System.Windows.Controls.FloatableWindow.OverlayOpacity" />
214 /// dependency property.
215 /// </summary>
216 /// <value>
217 /// The identifier for the
218 /// <see cref="P:System.Windows.Controls.FloatableWindow.OverlayOpacity" />
219 /// dependency property.
220 /// </value>
221 public static readonly DependencyProperty OverlayOpacityProperty =
222 DependencyProperty.Register(
223 "OverlayOpacity",
224 typeof(double),
225 typeof(FloatableWindow),
226 new PropertyMetadata(OnOverlayOpacityPropertyChanged));
227
228 /// <summary>
229 /// OverlayOpacityProperty PropertyChangedCallback call back static function.
230 /// </summary>
231 /// <param name="d">FloatableWindow object whose OverlayOpacity property is changed.</param>
232 /// <param name="e">DependencyPropertyChangedEventArgs which contains the old and new values.</param>
233 private static void OnOverlayOpacityPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
234 {
235 FloatableWindow cw = (FloatableWindow)d;
236
237 if (cw.Overlay != null)
238 {
239 cw.Overlay.Opacity = (double)e.NewValue;
240 }
241 }
242
243 #endregion public double OverlayOpacity
244
245 #region private static Control RootVisual
246
247 /// <summary>
248 /// Gets the root visual element.
249 /// </summary>
250 private static Control RootVisual
251 {
252 get
253 {
254 return Application.Current == null ? null : (Application.Current.RootVisual as Control);
255 }
256 }
257
258 #endregion private static Control RootVisual
259
260 #region public object Title
261
262 /// <summary>
263 /// Gets or sets the title that is displayed in the frame of the
264 /// <see cref="T:System.Windows.Controls.FloatableWindow" />.
265 /// </summary>
266 /// <value>
267 /// The title displayed at the top of the window. The default is null.
268 /// </value>
269 public object Title
270 {
271 get { return GetValue(TitleProperty); }
272 set { SetValue(TitleProperty, value); }
273 }
274
275 /// <summary>
276 /// Identifies the
277 /// <see cref="P:System.Windows.Controls.FloatableWindow.Title" />
278 /// dependency property.
279 /// </summary>
280 /// <value>
281 /// The identifier for the
282 /// <see cref="P:System.Windows.Controls.FloatableWindow.Title" />
283 /// dependency property.
284 /// </value>
285 public static readonly DependencyProperty TitleProperty =
286 DependencyProperty.Register(
287 "Title",
288 typeof(object),
289 typeof(FloatableWindow),
290 null);
291
292 #endregion public object Title
293
294 #endregion Static Fields and Constants
295
296 #region Member Fields
297 /// <summary>
298 /// Set in the overloaded Show method. Offsets the Popup vertically from the top left corner of the browser window by this amount.
299 /// </summary>
300 private double _verticalOffset;
301
302 /// <summary>
303 /// Set in the overloaded Show method. Offsets the Popup horizontally from the top left corner of the browser window by this amount.
304 /// </summary>
305 private double _horizontalOffset;
306
307 /// <summary>
308 /// Private accessor for the Resizer.
309 /// </summary>
310 private FrameworkElement _resizer;
311
312 /// <summary>
313 /// Private accessor for the IsModal
314 /// </summary>
315 [DefaultValue(false)]
316 private bool _modal;
317
318 /// <summary>
319 /// Private accessor for the Chrome.
320 /// </summary>
321 private FrameworkElement _chrome;
322
323 /// <summary>
324 /// Private accessor for the click point on the chrome.
325 /// </summary>
326 private Point _clickPoint;
327
328 /// <summary>
329 /// Private accessor for the Closing storyboard.
330 /// </summary>
331 private Storyboard _closed;
332
333 /// <summary>
334 /// Private accessor for the ContentPresenter.
335 /// </summary>
336 private FrameworkElement _contentPresenter;
337
338 /// <summary>
339 /// Private accessor for the translate transform that needs to be applied on to the ContentRoot.
340 /// </summary>
341 private TranslateTransform _contentRootTransform;
342
343 /// <summary>
344 /// Content area desired width.
345 /// </summary>
346 private double _desiredContentWidth;
347
348 /// <summary>
349 /// Content area desired height.
350 /// </summary>
351 private double _desiredContentHeight;
352
353 /// <summary>
354 /// Desired margin for the window.
355 /// </summary>
356 private Thickness _desiredMargin;
357
358 /// <summary>
359 /// Private accessor for the Dialog Result property.
360 /// </summary>
361 private bool? _dialogresult;
362
363 /// <summary>
364 /// Private accessor for the FloatableWindow InteractionState.
365 /// </summary>
366 private WindowInteractionState _interactionState;
367
368 /// <summary>
369 /// Boolean value that specifies whether the application is exit or not.
370 /// </summary>
371 private bool _isAppExit;
372
373 /// <summary>
374 /// Boolean value that specifies whether the window is in closing state or not.
375 /// </summary>
376 private bool _isClosing;
377
378 /// <summary>
379 /// Boolean value that specifies whether the window is opened.
380 /// </summary>
381 private bool _isOpen;
382
383 /// <summary>
384 /// Private accessor for the Opening storyboard.
385 /// </summary>
386 private Storyboard _opened;
387
388 /// <summary>
389 /// Boolean value that specifies whether the mouse is captured or not.
390 /// </summary>
391 private bool _isMouseCaptured;
392
393 /// <summary>
394 /// Private accessor for the Root of the window.
395 /// </summary>
396 private FrameworkElement _root;
397
398 /// <summary>
399 /// Private accessor for the position of the window with respect to RootVisual.
400 /// </summary>
401 private Point _windowPosition;
402
403 private static int z;
404
405 #endregion Member Fields
406
407 #region Constructors
408
409 /// <summary>
410 /// Initializes a new instance of the
411 /// <see cref="T:System.Windows.Controls.FloatableWindow" /> class.
412 /// </summary>
413 public FloatableWindow()
414 {
415 this.DefaultStyleKey = typeof(FloatableWindow);
416 this.InteractionState = WindowInteractionState.NotResponding;
417 this.ResizeMode = ResizeMode.CanResize;
418 }
419
420 #endregion Constructors
421
422 #region Events
423
424 /// <summary>
425 /// Occurs when the <see cref="T:System.Windows.Controls.FloatableWindow" />
426 /// is closed.
427 /// </summary>
428 public event EventHandler Closed;
429
430 /// <summary>
431 /// Occurs when the <see cref="T:System.Windows.Controls.FloatableWindow" />
432 /// is closing.
433 /// </summary>
434 public event EventHandler<CancelEventArgs> Closing;
435
436 #endregion Events
437
438 #region Properties
439
440 public Panel ParentLayoutRoot
441 {
442 get;
443 set;
444 }
445
446 /// <summary>
447 /// Gets the internal accessor for the ContentRoot of the window.
448 /// </summary>
449 internal FrameworkElement ContentRoot
450 {
451 get;
452 private set;
453 }
454
455 /// <summary>
456 /// Setting for the horizontal positioning offset for start position
457 /// </summary>
458 public double HorizontalOffset
459 {
460 get { return _horizontalOffset; }
461 set { _horizontalOffset = value; }
462 }
463
464 /// <summary>
465 /// Setting for the vertical positioning offset for start position
466 /// </summary>
467 public double VerticalOffset
468 {
469 get { return _verticalOffset; }
470 set { _verticalOffset = value; }
471 }
472
473 /// <summary>
474 /// Gets the internal accessor for the modal of the window.
475 /// </summary>
476 public bool IsModal
477 {
478 get
479 {
480 return _modal;
481 }
482 }
483
484 /// <summary>
485 /// Gets or sets a value indicating whether the
486 /// <see cref="T:System.Windows.Controls.FloatableWindow" /> was accepted or
487 /// canceled.
488 /// </summary>
489 /// <value>
490 /// True if the child window was accepted; false if the child window was
491 /// canceled. The default is null.
492 /// </value>
493 [TypeConverter(typeof(NullableBoolConverter))]
494 public bool? DialogResult
495 {
496 get
497 {
498 return this._dialogresult;
499 }
500
501 set
502 {
503 if (this._dialogresult != value)
504 {
505 this._dialogresult = value;
506 this.Close();
507 }
508 }
509 }
510
511 /// <summary>
512 /// Gets the internal accessor for the PopUp of the window.
513 /// </summary>
514 internal Popup ChildWindowPopup
515 {
516 get;
517 private set;
518 }
519
520 /// <summary>
521 /// Gets the internal accessor for the close button of the window.
522 /// </summary>
523 internal ButtonBase CloseButton
524 {
525 get;
526 private set;
527 }
528
529 /// <summary>
530 /// Gets the InteractionState for the FloatableWindow.
531 /// </summary>
532 internal WindowInteractionState InteractionState
533 {
534 get
535 {
536 return this._interactionState;
537 }
538 private set
539 {
540 if (this._interactionState != value)
541 {
542 WindowInteractionState oldValue = this._interactionState;
543 this._interactionState = value;
544 FloatableWindowAutomationPeer peer = FloatableWindowAutomationPeer.FromElement(this) as FloatableWindowAutomationPeer;
545
546 if (peer != null)
547 {
548 peer.RaiseInteractionStatePropertyChangedEvent(oldValue, this._interactionState);
549 }
550 }
551 }
552 }
553
554 /// <summary>
555 /// Gets a value indicating whether the PopUp is open or not.
556 /// </summary>
557 private bool IsOpen
558 {
559 get
560 {
561 return (this.ChildWindowPopup != null && this.ChildWindowPopup.IsOpen) ||
562 ((ParentLayoutRoot != null) && (ParentLayoutRoot.Children.Contains(this)));
563 }
564 }
565
566 /// <summary>
567 /// Gets the internal accessor for the overlay of the window.
568 /// </summary>
569 internal Panel Overlay
570 {
571 get;
572 private set;
573 }
574
575 public ResizeMode ResizeMode
576 {
577 get;
578 set;
579 }
580
581 #endregion Properties
582
583 #region Static Methods
584
585 /// <summary>
586 /// Inverts the input matrix.
587 /// </summary>
588 /// <param name="matrix">The matrix values that is to be inverted.</param>
589 /// <returns>Returns a value indicating whether the inversion was successful or not.</returns>
590 private static bool InvertMatrix(ref Matrix matrix)
591 {
592 double determinant = (matrix.M11 * matrix.M22) - (matrix.M12 * matrix.M21);
593
594 if (determinant == 0.0)
595 {
596 return false;
597 }
598
599 Matrix matCopy = matrix;
600 matrix.M11 = matCopy.M22 / determinant;
601 matrix.M12 = -1 * matCopy.M12 / determinant;
602 matrix.M21 = -1 * matCopy.M21 / determinant;
603 matrix.M22 = matCopy.M11 / determinant;
604 matrix.OffsetX = ((matCopy.OffsetY * matCopy.M21) - (matCopy.OffsetX * matCopy.M22)) / determinant;
605 matrix.OffsetY = ((matCopy.OffsetX * matCopy.M12) - (matCopy.OffsetY * matCopy.M11)) / determinant;
606
607 return true;
608 }
609
610 #endregion Static Methods
611
612 #region Methods
613
614 /// <summary>
615 /// Executed when the application is exited.
616 /// </summary>
617 /// <param name="sender">The sender.</param>
618 /// <param name="e">Event args.</param>
619 internal void Application_Exit(object sender, EventArgs e)
620 {
621 if (this.IsOpen)
622 {
623 this._isAppExit = true;
624 try
625 {
626 this.Close();
627 }
628 finally
629 {
630 this._isAppExit = false;
631 }
632 }
633 }
634
635 /// <summary>
636 /// Executed when focus is given to the window via a click. Attempts to bring current
637 /// window to the front in the event there are more windows.
638 /// </summary>
639 internal void BringToFront()
640 {
641 z++;
642 Canvas.SetZIndex(this, z);
643 #if DEBUG
644 this.Title = z.ToString();
645 #endif
646 }
647
648 /// <summary>
649 /// Changes the visual state of the FloatableWindow.
650 /// </summary>
651 private void ChangeVisualState()
652 {
653 if (this._isClosing)
654 {
655 VisualStateManager.GoToState(this, VSMSTATE_StateClosed, true);
656 }
657 else
658 {
659 VisualStateManager.GoToState(this, VSMSTATE_StateOpen, true);
660 BringToFront();
661 }
662 }
663
664 /// <summary>
665 /// Executed when FloatableWindow size is changed.
666 /// </summary>
667 /// <param name="sender">Sender object.</param>
668 /// <param name="e">Size changed event args.</param>
669 private void ChildWindow_SizeChanged(object sender, SizeChangedEventArgs e)
670 {
671 if (_modal)
672 {
673 if (this.Overlay != null)
674 {
675 if (e.NewSize.Height != this.Overlay.Height)
676 {
677 this._desiredContentHeight = e.NewSize.Height;
678 }
679
680 if (e.NewSize.Width != this.Overlay.Width)
681 {
682 this._desiredContentWidth = e.NewSize.Width;
683 }
684 }
685
686 if (this.IsOpen)
687 {
688 this.UpdateOverlaySize();
689 }
690 }
691 }
692
693 /// <summary>
694 /// Closes a <see cref="T:System.Windows.Controls.FloatableWindow" />.
695 /// </summary>
696 public void Close()
697 {
698 // AutomationPeer returns "Closing" when Close() is called
699 // but the window is not closed completely:
700 this.InteractionState = WindowInteractionState.Closing;
701 CancelEventArgs e = new CancelEventArgs();
702 this.OnClosing(e);
703
704 // On ApplicationExit, close() cannot be cancelled
705 if (!e.Cancel || this._isAppExit)
706 {
707 if (RootVisual != null)
708 {
709 RootVisual.IsEnabled = true;
710 }
711
712 // Close Popup
713 if (this.IsOpen)
714 {
715 if (this._closed != null)
716 {
717 // Popup will be closed when the storyboard ends
718 this._isClosing = true;
719 try
720 {
721 var sb = GetVisualStateStoryboard("WindowStates", "Closed");
722 sb.Completed += (s, args) =>
723 {
724 this.ParentLayoutRoot.Children.Remove(this);
725 this.OnClosed(EventArgs.Empty);
726 this.UnSubscribeFromEvents();
727 this.UnsubscribeFromTemplatePartEvents();
728
729 if (Application.Current.RootVisual != null)
730 {
731 Application.Current.RootVisual.GotFocus -= new RoutedEventHandler(this.RootVisual_GotFocus);
732 }
733 };
734 this.ChangeVisualState();
735 }
736 finally
737 {
738 this._isClosing = false;
739 }
740 }
741 else
742 {
743 // If no closing storyboard is defined, close the Popup
744 this.ChildWindowPopup.IsOpen = false;
745 }
746
747 if (!this._dialogresult.HasValue)
748 {
749 // If close action is not happening because of DialogResult property change action,
750 // Dialogresult is always false:
751 this._dialogresult = false;
752 }
753
754 //this.OnClosed(EventArgs.Empty);
755 //this.UnSubscribeFromEvents();
756 //this.UnsubscribeFromTemplatePartEvents();
757
758 //if (Application.Current.RootVisual != null)
759 //{
760 // Application.Current.RootVisual.GotFocus -= new RoutedEventHandler(this.RootVisual_GotFocus);
761 //}
762 }
763 }
764 else
765 {
766 // If the Close is cancelled, DialogResult should always be NULL:
767 this._dialogresult = null;
768 this.InteractionState = WindowInteractionState.Running;
769 }
770 }
771
772 /// <summary>
773 /// Brings the window to the front of others
774 /// </summary>
775 /// <param name="sender"></param>
776 /// <param name="e"></param>
777 internal void ContentRoot_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
778 {
779 BringToFront();
780 }
781
782 /// <summary>
783 /// Executed when the CloseButton is clicked.
784 /// </summary>
785 /// <param name="sender">Sender object.</param>
786 /// <param name="e">Routed event args.</param>
787 internal void CloseButton_Click(object sender, RoutedEventArgs e)
788 {
789 this.Close();
790 }
791
792 /// <summary>
793 /// Executed when the Closing storyboard ends.
794 /// </summary>
795 /// <param name="sender">Sender object.</param>
796 /// <param name="e">Event args.</param>
797 private void Closing_Completed(object sender, EventArgs e)
798 {
799 if (this.ChildWindowPopup != null)
800 {
801 this.ChildWindowPopup.IsOpen = false;
802 }
803
804 // AutomationPeer returns "NotResponding" when the FloatableWindow is closed:
805 this.InteractionState = WindowInteractionState.NotResponding;
806
807 if (this._closed != null)
808 {
809 this._closed.Completed -= new EventHandler(this.Closing_Completed);
810 }
811 }
812
813 /// <summary>
814 /// Executed when the a key is presses when the window is open.
815 /// </summary>
816 /// <param name="sender">Sender object.</param>
817 /// <param name="e">Key event args.</param>
818 private void ChildWindow_KeyDown(object sender, KeyEventArgs e)
819 {
820 FloatableWindow ew = sender as FloatableWindow;
821 Debug.Assert(ew != null, "FloatableWindow instance is null.");
822
823 // Ctrl+Shift+F4 closes the FloatableWindow
824 if (e != null && !e.Handled && e.Key == Key.F4 &&
825 ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control) &&
826 ((Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift))
827 {
828 ew.Close();
829 e.Handled = true;
830 }
831 }
832
833 /// <summary>
834 /// Executed when the window loses focus.
835 /// </summary>
836 /// <param name="sender">Sender object.</param>
837 /// <param name="e">Routed event args.</param>
838 private void ChildWindow_LostFocus(object sender, RoutedEventArgs e)
839 {
840 // If the FloatableWindow loses focus but the popup is still open,
841 // it means another popup is opened. To get the focus back when the
842 // popup is closed, we handle GotFocus on the RootVisual
843 // TODO: Something else could get focus and handle the GotFocus event right.
844 // Try listening to routed events that were Handled (new SL 3 feature)
845 // Blocked by Jolt bug #29419
846 if (this.IsOpen && Application.Current != null && Application.Current.RootVisual != null)
847 {
848 this.InteractionState = WindowInteractionState.BlockedByModalWindow;
849 Application.Current.RootVisual.GotFocus += new RoutedEventHandler(this.RootVisual_GotFocus);
850 }
851 }
852
853 /// <summary>
854 /// Executed when mouse left button is down on the chrome.
855 /// </summary>
856 /// <param name="sender">Sender object.</param>
857 /// <param name="e">Mouse button event args.</param>
858 private void Chrome_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
859 {
860 if (this._chrome != null)
861 {
862 e.Handled = true;
863
864 if (this.CloseButton != null && !this.CloseButton.IsTabStop)
865 {
866 this.CloseButton.IsTabStop = true;
867 try
868 {
869 this.Focus();
870 }
871 finally
872 {
873 this.CloseButton.IsTabStop = false;
874 }
875 }
876 else
877 {
878 this.Focus();
879 }
880 this._chrome.CaptureMouse();
881 this._isMouseCaptured = true;
882 this._clickPoint = e.GetPosition(sender as UIElement);
883 #if DEBUG
884 this.Title = string.Format("X:{0},Y:{1}", this._clickPoint.X.ToString(), this._clickPoint.Y.ToString());
885 #endif
886 }
887 }
888
889 /// <summary>
890 /// Executed when mouse left button is up on the chrome.
891 /// </summary>
892 /// <param name="sender">Sender object.</param>
893 /// <param name="e">Mouse button event args.</param>
894 private void Chrome_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
895 {
896 if (this._chrome != null)
897 {
898 //e.Handled = true;
899 this._chrome.ReleaseMouseCapture();
900 this._isMouseCaptured = false;
901 }
902 }
903
904 /// <summary>
905 /// Executed when mouse moves on the chrome.
906 /// </summary>
907 /// <param name="sender">Sender object.</param>
908 /// <param name="e">Mouse event args.</param>
909 private void Chrome_MouseMove(object sender, MouseEventArgs e)
910 {
911 #region New ChildWindow Code not working
912 //if (this._isMouseCaptured && this.ContentRoot != null && Application.Current != null && Application.Current.RootVisual != null)
913 //{
914 // Point position = e.GetPosition(Application.Current.RootVisual);
915
916 // GeneralTransform gt = this.ContentRoot.TransformToVisual(Application.Current.RootVisual);
917
918 // if (gt != null)
919 // {
920 // Point p = gt.Transform(this._clickPoint);
921 // this._windowPosition = gt.Transform(new Point(0, 0));
922
923 // if (position.X < 0)
924 // {
925 // double Y = FindPositionY(p, position, 0);
926 // position = new Point(0, Y);
927 // }
928
929 // if (position.X > this.Width)
930 // {
931 // double Y = FindPositionY(p, position, this.Width);
932 // position = new Point(this.Width, Y);
933 // }
934
935 // if (position.Y < 0)
936 // {
937 // double X = FindPositionX(p, position, 0);
938 // position = new Point(X, 0);
939 // }
940
941 // if (position.Y > this.Height)
942 // {
943 // double X = FindPositionX(p, position, this.Height);
944 // position = new Point(X, this.Height);
945 // }
946
947 // double x = position.X - p.X;
948 // double y = position.Y - p.Y;
949 // UpdateContentRootTransform(x, y);
950 // }
951 //}
952 #endregion
953 if (this._isMouseCaptured && this.ContentRoot != null)
954 {
955 // If the child window is dragged out of the page, return
956 if (Application.Current != null && Application.Current.RootVisual != null &&
957 (e.GetPosition(Application.Current.RootVisual).X < 0 || e.GetPosition(Application.Current.RootVisual).Y < 0))
958 {
959 return;
960 }
961
962 TransformGroup transformGroup = this.ContentRoot.RenderTransform as TransformGroup;
963
964 if (transformGroup == null)
965 {
966 transformGroup = new TransformGroup();
967 transformGroup.Children.Add(this.ContentRoot.RenderTransform);
968 }
969
970 TranslateTransform t = new TranslateTransform();
971 t.X = e.GetPosition(this.ContentRoot).X - this._clickPoint.X;
972 t.Y = e.GetPosition(this.ContentRoot).Y - this._clickPoint.Y;
973 if (transformGroup != null)
974 {
975 transformGroup.Children.Add(t);
976 this.ContentRoot.RenderTransform = transformGroup;
977 }
978 }
979 }
980
981 /// <summary>
982 /// Executed when the ContentPresenter size changes.
983 /// </summary>
984 /// <param name="sender">Content Presenter object.</param>
985 /// <param name="e">SizeChanged event args.</param>
986 private void ContentPresenter_SizeChanged(object sender, SizeChangedEventArgs e)
987 {
988 // timheuer: not sure really why this is here?
989 //if (this.ContentRoot != null && Application.Current != null && Application.Current.RootVisual != null && _isOpen)
990 //{
991 // GeneralTransform gt = this.ContentRoot.TransformToVisual(Application.Current.RootVisual);
992
993 // if (gt != null)
994 // {
995 // Point p = gt.Transform(new Point(0, 0));
996
997 // double x = this._windowPosition.X - p.X;
998 // double y = this._windowPosition.Y - p.Y;
999 // UpdateContentRootTransform(x, y);
1000 // }
1001 //}
1002
1003 //RectangleGeometry rg = new RectangleGeometry();
1004 //rg.Rect = new Rect(0, 0, this._contentPresenter.ActualWidth, this._contentPresenter.ActualHeight);
1005 //this._contentPresenter.Clip = rg;
1006 //this.UpdatePosition();
1007 }
1008
1009 /// <summary>
1010 /// Finds the X coordinate of a point that is defined by a line.
1011 /// </summary>
1012 /// <param name="p1">Starting point of the line.</param>
1013 /// <param name="p2">Ending point of the line.</param>
1014 /// <param name="y">Y coordinate of the point.</param>
1015 /// <returns>X coordinate of the point.</returns>
1016 private static double FindPositionX(Point p1, Point p2, double y)
1017 {
1018 if (y == p1.Y || p1.X == p2.X)
1019 {
1020 return p2.X;
1021 }
1022
1023 Debug.Assert(p1.Y != p2.Y, "Unexpected equal Y coordinates");
1024
1025 return (((y - p1.Y) * (p1.X - p2.X)) / (p1.Y - p2.Y)) + p1.X;
1026 }
1027
1028 /// <summary>
1029 /// Finds the Y coordinate of a point that is defined by a line.
1030 /// </summary>
1031 /// <param name="p1">Starting point of the line.</param>
1032 /// <param name="p2">Ending point of the line.</param>
1033 /// <param name="x">X coordinate of the point.</param>
1034 /// <returns>Y coordinate of the point.</returns>
1035 private static double FindPositionY(Point p1, Point p2, double x)
1036 {
1037 if (p1.Y == p2.Y || x == p1.X)
1038 {
1039 return p2.Y;
1040 }
1041
1042 Debug.Assert(p1.X != p2.X, "Unexpected equal X coordinates");
1043
1044 return (((p1.Y - p2.Y) * (x - p1.X)) / (p1.X - p2.X)) + p1.Y;
1045 }
1046
1047 /// <summary>
1048 /// Builds the visual tree for the
1049 /// <see cref="T:System.Windows.Controls.FloatableWindow" /> control when a
1050 /// new template is applied.
1051 /// </summary>
1052 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "No need to split the code into two parts.")]
1053 public override void OnApplyTemplate()
1054 {
1055 this.UnsubscribeFromTemplatePartEvents();
1056
1057 base.OnApplyTemplate();
1058
1059 this.CloseButton = GetTemplateChild(PART_CloseButton) as ButtonBase;
1060
1061 if (this.CloseButton != null)
1062 {
1063 if (this.HasCloseButton)
1064 {
1065 this.CloseButton.Visibility = Visibility.Visible;
1066 }
1067 else
1068 {
1069 this.CloseButton.Visibility = Visibility.Collapsed;
1070 }
1071 }
1072
1073 if (this._closed != null)
1074 {
1075 this._closed.Completed -= new EventHandler(this.Closing_Completed);
1076 }
1077
1078 if (this._opened != null)
1079 {
1080 this._opened.Completed -= new EventHandler(this.Opening_Completed);
1081 }
1082
1083 this._root = GetTemplateChild(PART_Root) as FrameworkElement;
1084 this._resizer = GetTemplateChild(PART_Resizer) as FrameworkElement;
1085
1086 if (this._root != null)
1087 {
1088 IList groups = VisualStateManager.GetVisualStateGroups(this._root);
1089
1090 if (groups != null)
1091 {
1092 IList states = null;
1093
1094 foreach (VisualStateGroup vsg in groups)
1095 {
1096 if (vsg.Name == FloatableWindow.VSMGROUP_Window)
1097 {
1098 states = vsg.States;
1099 break;
1100 }
1101 }
1102
1103 if (states != null)
1104 {
1105 foreach (VisualState state in states)
1106 {
1107 if (state.Name == FloatableWindow.VSMSTATE_StateClosed)
1108 {
1109 this._closed = state.Storyboard;
1110 }
1111
1112 if (state.Name == FloatableWindow.VSMSTATE_StateOpen)
1113 {
1114 this._opened = state.Storyboard;
1115 }
1116 }
1117 }
1118 }
1119 //TODO: Figure out why I can't wire up the event below in SubscribeToTemplatePartEvents
1120 this._root.MouseLeftButtonDown += new MouseButtonEventHandler(this.ContentRoot_MouseLeftButtonDown);
1121
1122 if (this.ResizeMode == ResizeMode.CanResize)
1123 {
1124 this._resizer.MouseLeftButtonDown += new System.Windows.Input.MouseButtonEventHandler(Resizer_MouseLeftButtonDown);
1125 this._resizer.MouseLeftButtonUp += new System.Windows.Input.MouseButtonEventHandler(Resizer_MouseLeftButtonUp);
1126 this._resizer.MouseMove += new System.Windows.Input.MouseEventHandler(Resizer_MouseMove);
1127 this._resizer.MouseEnter += new MouseEventHandler(Resizer_MouseEnter);
1128 this._resizer.MouseLeave += new MouseEventHandler(Resizer_MouseLeave);
1129 }
1130 else
1131 {
1132 this._resizer.Opacity = 0;
1133 }
1134 }
1135
1136 this.ContentRoot = GetTemplateChild(PART_ContentRoot) as FrameworkElement;
1137
1138 this._chrome = GetTemplateChild(PART_Chrome) as FrameworkElement;
1139
1140 this.Overlay = GetTemplateChild(PART_Overlay) as Panel;
1141
1142 this._contentPresenter = GetTemplateChild(PART_ContentPresenter) as FrameworkElement;
1143
1144 this.SubscribeToTemplatePartEvents();
1145 this.SubscribeToStoryBoardEvents();
1146 this._desiredMargin = this.Margin;
1147 this.Margin = new Thickness(0);
1148
1149 // Update overlay size
1150 if (this.IsOpen && (this.ChildWindowPopup != null))
1151 {
1152 this._desiredContentHeight = this.Height;
1153 this._desiredContentWidth = this.Width;
1154 this.UpdateOverlaySize();
1155 this.UpdateRenderTransform();
1156 this.ChangeVisualState();
1157 }
1158 }
1159
1160 void Resizer_MouseLeave(object sender, MouseEventArgs e)
1161 {
1162 if (!this._isMouseCaptured)
1163 {
1164 this._resizer.Opacity = .25;
1165 }
1166 }
1167
1168 void Resizer_MouseEnter(object sender, MouseEventArgs e)
1169 {
1170 if (!this._isMouseCaptured)
1171 {
1172 this._resizer.Opacity = 1;
1173 }
1174 }
1175
1176 /// <summary>
1177 /// Raises the
1178 /// <see cref="E:System.Windows.Controls.FloatableWindow.Closed" /> event.
1179 /// </summary>
1180 /// <param name="e">The event data.</param>
1181 protected virtual void OnClosed(EventArgs e)
1182 {
1183 EventHandler handler = this.Closed;
1184
1185 if (null != handler)
1186 {
1187 handler(this, e);
1188 }
1189
1190 this._isOpen = false;
1191 if (!_modal)
1192 {
1193 this.ParentLayoutRoot.Children.Remove(this);
1194 }
1195 }
1196
1197 /// <summary>
1198 /// Raises the
1199 /// <see cref="E:System.Windows.Controls.FloatableWindow.Closing" /> event.
1200 /// </summary>
1201 /// <param name="e">The event data.</param>
1202 protected virtual void OnClosing(CancelEventArgs e)
1203 {
1204 EventHandler<CancelEventArgs> handler = this.Closing;
1205
1206 if (null != handler)
1207 {
1208 handler(this, e);
1209 }
1210 }
1211
1212 /// <summary>
1213 /// Returns a
1214 /// <see cref="T:System.Windows.Automation.Peers.FloatableWindowAutomationPeer" />
1215 /// for use by the Silverlight automation infrastructure.
1216 /// </summary>
1217 /// <returns>
1218 /// <see cref="T:System.Windows.Automation.Peers.FloatableWindowAutomationPeer" />
1219 /// for the <see cref="T:System.Windows.Controls.FloatableWindow" /> object.
1220 /// </returns>
1221 protected override AutomationPeer OnCreateAutomationPeer()
1222 {
1223 return new FloatableWindowAutomationPeer(this);
1224 }
1225
1226 /// <summary>
1227 /// This method is called every time a
1228 /// <see cref="T:System.Windows.Controls.FloatableWindow" /> is displayed.
1229 /// </summary>
1230 protected virtual void OnOpened()
1231 {
1232 this.UpdatePosition();
1233 this._isOpen = true;
1234
1235 if (this.Overlay != null)
1236 {
1237 this.Overlay.Opacity = this.OverlayOpacity;
1238 this.Overlay.Background = this.OverlayBrush;
1239 }
1240
1241 if (!this.Focus())
1242 {
1243 // If the Focus() fails it means there is no focusable element in the
1244 // FloatableWindow. In this case we set IsTabStop to true to have the keyboard functionality
1245 this.IsTabStop = true;
1246 this.Focus();
1247 }
1248 }
1249
1250 /// <summary>
1251 /// Executed when the opening storyboard finishes.
1252 /// </summary>
1253 /// <param name="sender">Sender object.</param>
1254 /// <param name="e">Event args.</param>
1255 private void Opening_Completed(object sender, EventArgs e)
1256 {
1257 if (this._opened != null)
1258 {
1259 this._opened.Completed -= new EventHandler(this.Opening_Completed);
1260 }
1261 // AutomationPeer returns "ReadyForUserInteraction" when the FloatableWindow
1262 // is open and all animations have been completed.
1263 this.InteractionState = WindowInteractionState.ReadyForUserInteraction;
1264 this.OnOpened();
1265 }
1266
1267 /// <summary>
1268 /// Executed when the page resizes.
1269 /// </summary>
1270 /// <param name="sender">Sender object.</param>
1271 /// <param name="e">Event args.</param>
1272 private void Page_Resized(object sender, EventArgs e)
1273 {
1274 if (this.ChildWindowPopup != null)
1275 {
1276 this.UpdateOverlaySize();
1277 }
1278 }
1279
1280 /// <summary>
1281 /// Executed when the root visual gets focus.
1282 /// </summary>
1283 /// <param name="sender">Sender object.</param>
1284 /// <param name="e">Routed event args.</param>
1285 private void RootVisual_GotFocus(object sender, RoutedEventArgs e)
1286 {
1287 this.Focus();
1288 this.InteractionState = WindowInteractionState.ReadyForUserInteraction;
1289 }
1290
1291 public void Show()
1292 {
1293 ShowWindow(false);
1294 }
1295
1296 public void ShowDialog()
1297 {
1298 _verticalOffset = 0;
1299 _horizontalOffset = 0;
1300 ShowWindow(true);
1301 }
1302
1303 public void Show(double horizontalOffset, double verticalOffset)
1304 {
1305 _horizontalOffset = horizontalOffset;
1306 _verticalOffset = verticalOffset;
1307 ShowWindow(false);
1308 }
1309
1310 /// <summary>
1311 /// Opens a <see cref="T:System.Windows.Controls.FloatableWindow" /> and
1312 /// returns without waiting for the
1313 /// <see cref="T:System.Windows.Controls.FloatableWindow" /> to close.
1314 /// </summary>
1315 /// <exception cref="T:System.InvalidOperationException">
1316 /// The child window is already in the visual tree.
1317 /// </exception>
1318 internal void ShowWindow(bool isModal)
1319 {
1320 _modal = isModal;
1321
1322 // AutomationPeer returns "Running" when Show() is called
1323 // but the FloatableWindow is not ready for user interaction:
1324 this.InteractionState = WindowInteractionState.Running;
1325
1326 this.SubscribeToEvents();
1327 this.SubscribeToTemplatePartEvents();
1328 this.SubscribeToStoryBoardEvents();
1329
1330
1331 // MaxHeight and MinHeight properties should not be overwritten:
1332 this.MaxHeight = double.PositiveInfinity;
1333 this.MaxWidth = double.PositiveInfinity;
1334
1335 if (_modal)
1336 {
1337 if (this.ChildWindowPopup == null)
1338 {
1339 this.ChildWindowPopup = new Popup();
1340
1341 try
1342 {
1343 this.ChildWindowPopup.Child = this;
1344 }
1345 catch (ArgumentException)
1346 {
1347 // If the FloatableWindow is already in the visualtree, we cannot set it to be the child of the popup
1348 // we are throwing a friendlier exception for this case:
1349 this.InteractionState = WindowInteractionState.NotResponding;
1350 throw new InvalidOperationException(Properties.Resources.ChildWindow_InvalidOperation);
1351 }
1352 }
1353
1354 if (this.ChildWindowPopup != null && Application.Current.RootVisual != null)
1355 {
1356 this.ChildWindowPopup.IsOpen = true;
1357
1358 this.ChildWindowPopup.HorizontalOffset = _horizontalOffset;
1359 this.ChildWindowPopup.VerticalOffset = _verticalOffset;
1360
1361 // while the FloatableWindow is open, the DialogResult is always NULL:
1362 this._dialogresult = null;
1363 }
1364 }
1365 else
1366 {
1367 if (ParentLayoutRoot != null)
1368 {
1369 this.SetValue(Canvas.TopProperty, _verticalOffset);
1370 this.SetValue(Canvas.LeftProperty, _horizontalOffset);
1371 this.ParentLayoutRoot.Children.Add(this);
1372 this.BringToFront();
1373 }
1374 else
1375 {
1376 throw new ArgumentNullException("ParentLayoutRoot", "You need to specify a root Panel element to add the window elements to.");
1377 }
1378 }
1379
1380 // disable the underlying UI
1381 if (RootVisual != null && _modal)
1382 {
1383 RootVisual.IsEnabled = false;
1384 }
1385
1386 // if the template is already loaded, display loading visuals animation
1387 if (this.ContentRoot == null)
1388 {
1389 this.Loaded += (s, args) =>
1390 {
1391 if (this.ContentRoot != null)
1392 {
1393 this.ChangeVisualState();
1394 }
1395 };
1396 }
1397 else
1398 {
1399 this.ChangeVisualState();
1400 }
1401 }
1402
1403 /// <summary>
1404 /// Subscribes to events when the FloatableWindow is opened.
1405 /// </summary>
1406 private void SubscribeToEvents()
1407 {
1408 if (Application.Current != null && Application.Current.Host != null && Application.Current.Host.Content != null)
1409 {
1410 Application.Current.Exit += new EventHandler(this.Application_Exit);
1411 Application.Current.Host.Content.Resized += new EventHandler(this.Page_Resized);
1412 }
1413
1414 this.KeyDown += new KeyEventHandler(this.ChildWindow_KeyDown);
1415 if (_modal)
1416 {
1417 this.LostFocus += new RoutedEventHandler(this.ChildWindow_LostFocus);
1418 }
1419 this.SizeChanged += new SizeChangedEventHandler(this.ChildWindow_SizeChanged);
1420 }
1421
1422 /// <summary>
1423 /// Subscribes to events that are on the storyboards.
1424 /// Unsubscribing from these events happen in the event handlers individually.
1425 /// </summary>
1426 private void SubscribeToStoryBoardEvents()
1427 {
1428 if (this._closed != null)
1429 {
1430 this._closed.Completed += new EventHandler(this.Closing_Completed);
1431 }
1432
1433 if (this._opened != null)
1434 {
1435 this._opened.Completed += new EventHandler(this.Opening_Completed);
1436 }
1437 }
1438
1439 /// <summary>
1440 /// Subscribes to events on the template parts.
1441 /// </summary>
1442 private void SubscribeToTemplatePartEvents()
1443 {
1444 if (this.CloseButton != null)
1445 {
1446 this.CloseButton.Click += new RoutedEventHandler(this.CloseButton_Click);
1447 }
1448
1449 if (this._chrome != null)
1450 {
1451 this._chrome.MouseLeftButtonDown += new MouseButtonEventHandler(this.Chrome_MouseLeftButtonDown);
1452 this._chrome.MouseLeftButtonUp += new MouseButtonEventHandler(this.Chrome_MouseLeftButtonUp);
1453 this._chrome.MouseMove += new MouseEventHandler(this.Chrome_MouseMove);
1454 }
1455
1456 if (this._contentPresenter != null)
1457 {
1458 this._contentPresenter.SizeChanged += new SizeChangedEventHandler(this.ContentPresenter_SizeChanged);
1459 }
1460 }
1461
1462 /// <summary>
1463 /// Unsubscribe from events when the FloatableWindow is closed.
1464 /// </summary>
1465 private void UnSubscribeFromEvents()
1466 {
1467 if (Application.Current != null && Application.Current.Host != null && Application.Current.Host.Content != null)
1468 {
1469 Application.Current.Exit -= new EventHandler(this.Application_Exit);
1470 Application.Current.Host.Content.Resized -= new EventHandler(this.Page_Resized);
1471 }
1472
1473 this.KeyDown -= new KeyEventHandler(this.ChildWindow_KeyDown);
1474 if (_modal)
1475 {
1476 this.LostFocus -= new RoutedEventHandler(this.ChildWindow_LostFocus);
1477 }
1478 this.SizeChanged -= new SizeChangedEventHandler(this.ChildWindow_SizeChanged);
1479 }
1480
1481 /// <summary>
1482 /// Unsubscribe from the events that are subscribed on the template part elements.
1483 /// </summary>
1484 private void UnsubscribeFromTemplatePartEvents()
1485 {
1486 if (this.CloseButton != null)
1487 {
1488 this.CloseButton.Click -= new RoutedEventHandler(this.CloseButton_Click);
1489 }
1490
1491 if (this._chrome != null)
1492 {
1493 this._chrome.MouseLeftButtonDown -= new MouseButtonEventHandler(this.Chrome_MouseLeftButtonDown);
1494 this._chrome.MouseLeftButtonUp -= new MouseButtonEventHandler(this.Chrome_MouseLeftButtonUp);
1495 this._chrome.MouseMove -= new MouseEventHandler(this.Chrome_MouseMove);
1496 }
1497
1498 if (this._contentPresenter != null)
1499 {
1500 this._contentPresenter.SizeChanged -= new SizeChangedEventHandler(this.ContentPresenter_SizeChanged);
1501 }
1502 }
1503
1504 /// <summary>
1505 /// Updates the size of the overlay of the window.
1506 /// </summary>
1507 private void UpdateOverlaySize()
1508 {
1509 if (_modal)
1510 {
1511 if (this.Overlay != null && Application.Current != null && Application.Current.Host != null && Application.Current.Host.Content != null)
1512 {
1513 this.Height = Application.Current.Host.Content.ActualHeight;
1514 this.Width = Application.Current.Host.Content.ActualWidth;
1515 this.Overlay.Height = this.Height;
1516 this.Overlay.Width = this.Width;
1517
1518 if (this.ContentRoot != null)
1519 {
1520 this.ContentRoot.Width = this._desiredContentWidth;
1521 this.ContentRoot.Height = this._desiredContentHeight;
1522 this.ContentRoot.Margin = this._desiredMargin;
1523 }
1524 }
1525 }
1526 else
1527 {
1528 if (this.Overlay != null)
1529 {
1530 this.Overlay.Visibility = Visibility.Collapsed;
1531 }
1532 }
1533 }
1534
1535 /// <summary>
1536 /// Updates the position of the window in case the size of the content changes.
1537 /// This allows FloatableWindow only scale from right and bottom.
1538 /// </summary>
1539 private void UpdatePosition()
1540 {
1541 if (this.ContentRoot != null && Application.Current != null && Application.Current.RootVisual != null)
1542 {
1543 GeneralTransform gt = this.ContentRoot.TransformToVisual(Application.Current.RootVisual);
1544
1545 if (gt != null)
1546 {
1547 this._windowPosition = gt.Transform(new Point(0, 0));
1548 }
1549 }
1550 }
1551
1552 /// <summary>
1553 /// Updates the render transform applied on the overlay.
1554 /// </summary>
1555 private void UpdateRenderTransform()
1556 {
1557 if (this._root != null && this.ContentRoot != null)
1558 {
1559 // The Overlay part should not be affected by the render transform applied on the
1560 // FloatableWindow. In order to achieve this, we adjust an identity matrix to represent
1561 // the _root's transformation, invert it, apply the inverted matrix on the _root, so that
1562 // nothing is affected by the rendertransform, and apply the original transform only on the Content
1563 GeneralTransform gt = this._root.TransformToVisual(null);
1564 if (gt != null)
1565 {
1566 Point p10 = new Point(1, 0);
1567 Point p01 = new Point(0, 1);
1568 Point transform10 = gt.Transform(p10);
1569 Point transform01 = gt.Transform(p01);
1570
1571 Matrix transformToRootMatrix = Matrix.Identity;
1572 transformToRootMatrix.M11 = transform10.X;
1573 transformToRootMatrix.M12 = transform10.Y;
1574 transformToRootMatrix.M21 = transform01.X;
1575 transformToRootMatrix.M22 = transform01.Y;
1576
1577 MatrixTransform original = new MatrixTransform();
1578 original.Matrix = transformToRootMatrix;
1579
1580 InvertMatrix(ref transformToRootMatrix);
1581 MatrixTransform mt = new MatrixTransform();
1582 mt.Matrix = transformToRootMatrix;
1583
1584 TransformGroup tg = this._root.RenderTransform as TransformGroup;
1585
1586 if (tg != null)
1587 {
1588 tg.Children.Add(mt);
1589 }
1590 else
1591 {
1592 this._root.RenderTransform = mt;
1593 }
1594
1595 tg = this.ContentRoot.RenderTransform as TransformGroup;
1596
1597 if (tg != null)
1598 {
1599 tg.Children.Add(original);
1600 }
1601 else
1602 {
1603 this.ContentRoot.RenderTransform = original;
1604 }
1605 }
1606 }
1607 }
1608
1609 /// <summary>
1610 /// Updates the ContentRootTranslateTransform.
1611 /// </summary>
1612 /// <param name="X">X coordinate of the transform.</param>
1613 /// <param name="Y">Y coordinate of the transform.</param>
1614 private void UpdateContentRootTransform(double X, double Y)
1615 {
1616 if (this._contentRootTransform == null)
1617 {
1618 this._contentRootTransform = new TranslateTransform();
1619 this._contentRootTransform.X = X;
1620 this._contentRootTransform.Y = Y;
1621
1622 TransformGroup transformGroup = this.ContentRoot.RenderTransform as TransformGroup;
1623
1624 if (transformGroup == null)
1625 {
1626 transformGroup = new TransformGroup();
1627 transformGroup.Children.Add(this.ContentRoot.RenderTransform);
1628 }
1629 transformGroup.Children.Add(this._contentRootTransform);
1630 this.ContentRoot.RenderTransform = transformGroup;
1631 }
1632 else
1633 {
1634 this._contentRootTransform.X += X;
1635 this._contentRootTransform.Y += Y;
1636 }
1637 }
1638
1639 private void Resizer_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
1640 {
1641 this._resizer.CaptureMouse();
1642 this._isMouseCaptured = true;
1643 this._clickPoint = e.GetPosition(sender as UIElement);
1644
1645 #if DEBUG
1646 this.Title = string.Format("X:{0},Y:{1}", this._clickPoint.X.ToString(), this._clickPoint.Y.ToString());
1647 #endif
1648 }
1649
1650 private void Resizer_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
1651 {
1652 this._resizer.ReleaseMouseCapture();
1653 this._isMouseCaptured = false;
1654 this._resizer.Opacity = 0.25;
1655 }
1656
1657 private void Resizer_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
1658 {
1659 if (this._isMouseCaptured && this.ContentRoot != null)
1660 {
1661 // If the child window is dragged out of the page, return
1662 if (Application.Current != null && Application.Current.RootVisual != null &&
1663 (e.GetPosition(Application.Current.RootVisual).X < 0 || e.GetPosition(Application.Current.RootVisual).Y < 0))
1664 {
1665 return;
1666 }
1667
1668 #if DEBUG
1669 this.Title = string.Format("X:{0},Y:{1}", this._clickPoint.X.ToString(), this._clickPoint.Y.ToString());
1670 #endif
1671
1672 Point p = e.GetPosition(this.ContentRoot);
1673
1674 if ((p.X > this._clickPoint.X) && (p.Y > this._clickPoint.Y))
1675 {
1676 this.Width = (double)(p.X - (12 - this._clickPoint.X));
1677 this.Height = (double)(p.Y - (12 - this._clickPoint.Y));
1678 }
1679 }
1680 }
1681
1682 private Storyboard GetVisualStateStoryboard(string visualStateGroupName, string visualStateName)
1683 {
1684 foreach (VisualStateGroup g in VisualStateManager.GetVisualStateGroups((FrameworkElement)this.ContentRoot.Parent))
1685 {
1686 if (g.Name != visualStateGroupName) continue;
1687 foreach (VisualState s in g.States)
1688 {
1689 if (s.Name != visualStateName) continue;
1690 return s.Storyboard;
1691 }
1692 }
1693 return null;
1694 }
1695
1696 #endregion Methods
1697 }
1698 }