Mercurial > silverbladetech
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 } |