0b4cf1b4b8d28a040dd9a2d4e4081d89cdf700a9
[mono.git] / mcs / class / referencesource / System.Activities.Presentation / System.Activities.Presentation / System / Activities / Presentation / Base / Core / Internal / PropertyEditing / FromExpression / Framework / Controls / WorkaroundPopup.cs
1 // -------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All Rights Reserved.
3 // -------------------------------------------------------------------
4 //From \\authoring\Sparkle\Source\1.0.1083.0\Common\Source\Framework\Controls
5 namespace System.Activities.Presentation.Internal.PropertyEditing.FromExpression.Framework.Controls
6 {
7     using System;
8     using System.Windows;
9     using System.Windows.Input;
10     using System.Windows.Controls.Primitives;
11     using System.Windows.Media;
12     using System.Activities.Presentation.Internal.PropertyEditing.FromExpression.Framework.UserInterface;
13
14     // <summary>
15     // This class contains specific behavior for the Popup associated with PropertyContainer.
16     // Basically, it is a workaround for Windows OS bug #1745919.  The "StaysOpen = false" setting
17     // on a Popup does not function as we expect when the Popup is created within another
18     // "StaysOpen = false" popup (or if anything has capture).  What happens is the Popup first
19     // checks if anything has capture, and only takes capture if nothing else has taken it.  But the
20     // StaysOpen behavior is implemented using the capture, so we lose that.  Also, related to that
21     // the Closed event will not be called, so to workaround both of those issues we essentially
22     // re-implement the popup capture grabbing code, except we take capture no matter what.
23     // </summary>
24     internal class WorkaroundPopup : Popup
25     {
26         private bool releasingCapture = false;
27
28         protected override void OnOpened(EventArgs e)
29         {
30             this.releasingCapture = false;
31
32             if (this.Child != null)
33             {
34                 this.Child.Focusable = true;
35                 this.Child.Focus();
36                 Mouse.Capture(this.Child, CaptureMode.SubTree);
37             }
38             this.SetValue(FocusScopeManager.FocusScopePriorityProperty, 1);
39             base.OnOpened(e);
40         }
41
42         protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e)
43         {
44             base.OnGotKeyboardFocus(e);
45         }
46
47         protected override void OnLostKeyboardFocus(KeyboardFocusChangedEventArgs e)
48         {
49             base.OnLostKeyboardFocus(e);
50         }
51
52         protected override void OnGotFocus(RoutedEventArgs e)
53         {
54             base.OnGotFocus(e);
55         }
56
57         protected override void OnLostFocus(RoutedEventArgs e)
58         {
59             base.OnLostFocus(e);
60         }
61
62         protected override void OnLostMouseCapture(System.Windows.Input.MouseEventArgs e)
63         {
64             object sender = this;
65             // This code is a stripped down implementation of Popup.OnMouseLostCapture
66             if (!this.releasingCapture && Mouse.Captured != this.Child)
67             {
68                 if (e.OriginalSource == this.Child)
69                 {
70                     if (Mouse.Captured == null)
71                     {
72                         this.IsOpen = false;
73                     }
74                 }
75                 else if (this.IsDescendentOfPopup(sender as DependencyObject))
76                 {
77                     if (this.IsOpen && Mouse.Captured == null)
78                     {
79                         Mouse.Capture(this.Child, CaptureMode.SubTree);
80                     }
81                 }
82                 else
83                 {
84                     this.IsOpen = false;
85                 }
86             }
87             base.OnLostMouseCapture(e);
88         }
89
90         protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
91         {
92             // Check if the mouse down occured within the popup, if it did, leave the popup open.  If it didn't, then close
93             // the popup and release capture.
94             if (e.OriginalSource == this.Child && this.Child.InputHitTest(e.GetPosition(this.Child)) == null)
95             {
96                 this.IsOpen = false;
97                 this.ReleaseChildMouseCapture();
98             }
99             base.OnMouseDown(e);
100         }
101
102         private bool IsDescendentOfPopup(DependencyObject currentObject)
103         {
104             while (currentObject != null)
105             {
106                 if (currentObject == this || currentObject == this.Child)
107                 {
108                     return true;
109                 }
110                 currentObject = VisualTreeHelper.GetParent(currentObject);
111             }
112
113             return false;
114         }
115
116         private void ReleaseChildMouseCapture()
117         {
118             if (Mouse.Captured == this.Child)
119             {
120                 this.releasingCapture = true;
121                 Mouse.Capture(null);
122                 this.releasingCapture = false;
123             }
124         }
125
126         protected override void OnKeyDown(KeyEventArgs e)
127         {
128             if (e.Key == Key.Escape)
129             {
130                 this.IsOpen = false;
131                 this.ReleaseChildMouseCapture();
132             }
133             base.OnKeyDown(e);
134         }
135
136         protected override void OnClosed(EventArgs e)
137         {
138             this.ReleaseChildMouseCapture();
139             base.OnClosed(e);
140         }
141     }
142 }