PageRenderTime 414ms CodeModel.GetById 141ms app.highlight 140ms RepoModel.GetById 121ms app.codeStats 1ms

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

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