File: System.Activities.Presentation\System\Activities\Presentation\Base\Core\Internal\PropertyEditing\FromExpression\Framework\Controls\WorkaroundPopup.cs
Project: ndp\cdf\src\NetFx40\Tools\System.Activities.Presentation.csproj (System.Activities.Presentation)
// -------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All Rights Reserved.
// -------------------------------------------------------------------
//From \\authoring\Sparkle\Source\1.0.1083.0\Common\Source\Framework\Controls
namespace System.Activities.Presentation.Internal.PropertyEditing.FromExpression.Framework.Controls
{
    using System;
    using System.Windows;
    using System.Windows.Input;
    using System.Windows.Controls.Primitives;
    using System.Windows.Media;
    using System.Activities.Presentation.Internal.PropertyEditing.FromExpression.Framework.UserInterface;
 
    // <summary>
    // This class contains specific behavior for the Popup associated with PropertyContainer.
    // Basically, it is a workaround for Windows OS bug #1745919.  The "StaysOpen = false" setting
    // on a Popup does not function as we expect when the Popup is created within another
    // "StaysOpen = false" popup (or if anything has capture).  What happens is the Popup first
    // checks if anything has capture, and only takes capture if nothing else has taken it.  But the
    // StaysOpen behavior is implemented using the capture, so we lose that.  Also, related to that
    // the Closed event will not be called, so to workaround both of those issues we essentially
    // re-implement the popup capture grabbing code, except we take capture no matter what.
    // </summary>
    internal class WorkaroundPopup : Popup
    {
        private bool releasingCapture = false;
 
        protected override void OnOpened(EventArgs e)
        {
            this.releasingCapture = false;
 
            if (this.Child != null)
            {
                this.Child.Focusable = true;
                this.Child.Focus();
                Mouse.Capture(this.Child, CaptureMode.SubTree);
            }
            this.SetValue(FocusScopeManager.FocusScopePriorityProperty, 1);
            base.OnOpened(e);
        }
 
        protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e)
        {
            base.OnGotKeyboardFocus(e);
        }
 
        protected override void OnLostKeyboardFocus(KeyboardFocusChangedEventArgs e)
        {
            base.OnLostKeyboardFocus(e);
        }
 
        protected override void OnGotFocus(RoutedEventArgs e)
        {
            base.OnGotFocus(e);
        }
 
        protected override void OnLostFocus(RoutedEventArgs e)
        {
            base.OnLostFocus(e);
        }
 
        protected override void OnLostMouseCapture(System.Windows.Input.MouseEventArgs e)
        {
            object sender = this;
            // This code is a stripped down implementation of Popup.OnMouseLostCapture
            if (!this.releasingCapture && Mouse.Captured != this.Child)
            {
                if (e.OriginalSource == this.Child)
                {
                    if (Mouse.Captured == null)
                    {
                        this.IsOpen = false;
                    }
                }
                else if (this.IsDescendentOfPopup(sender as DependencyObject))
                {
                    if (this.IsOpen && Mouse.Captured == null)
                    {
                        Mouse.Capture(this.Child, CaptureMode.SubTree);
                    }
                }
                else
                {
                    this.IsOpen = false;
                }
            }
            base.OnLostMouseCapture(e);
        }
 
        protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
        {
            // Check if the mouse down occured within the popup, if it did, leave the popup open.  If it didn't, then close
            // the popup and release capture.
            if (e.OriginalSource == this.Child && this.Child.InputHitTest(e.GetPosition(this.Child)) == null)
            {
                this.IsOpen = false;
                this.ReleaseChildMouseCapture();
            }
            base.OnMouseDown(e);
        }
 
        private bool IsDescendentOfPopup(DependencyObject currentObject)
        {
            while (currentObject != null)
            {
                if (currentObject == this || currentObject == this.Child)
                {
                    return true;
                }
                currentObject = VisualTreeHelper.GetParent(currentObject);
            }
 
            return false;
        }
 
        private void ReleaseChildMouseCapture()
        {
            if (Mouse.Captured == this.Child)
            {
                this.releasingCapture = true;
                Mouse.Capture(null);
                this.releasingCapture = false;
            }
        }
 
        protected override void OnKeyDown(KeyEventArgs e)
        {
            if (e.Key == Key.Escape)
            {
                this.IsOpen = false;
                this.ReleaseChildMouseCapture();
            }
            base.OnKeyDown(e);
        }
 
        protected override void OnClosed(EventArgs e)
        {
            this.ReleaseChildMouseCapture();
            base.OnClosed(e);
        }
    }
}