[amd64/tramp] hide interpreter specific trampoline behind ifdef
[mono.git] / mcs / class / referencesource / System.Activities.Presentation / System.Activities.Presentation / System / Activities / Presentation / Base / Core / Internal / PropertyEditing / EditModeSwitchButtonKeyboardFix.cs
1 //----------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //----------------------------------------------------------------
4 namespace System.Activities.Presentation.Internal.PropertyEditing 
5 {
6     using System;
7     using System.Diagnostics;
8     using System.Diagnostics.CodeAnalysis;
9     using System.Globalization;
10     using System.Windows;
11     using System.Windows.Input;
12     using System.Windows.Threading;
13     using System.Activities.Presentation.PropertyEditing;
14     using System.Runtime;
15     using System.Activities.Presentation;
16
17     // <summary>
18     // This is a fix for a bug in EditModeSwitchButton which lives in System.Activities.Presentation and
19     // which has already been locked as an assembly.  EditModeSwitchButton only responds to MouseDown
20     // events to make sure that the opening of the popup extended editor works correctly.  However,
21     // that means that it will never respond to keyboard or automation events.  To fix it, this class
22     // offers up an attached DP that, when used, hooks into events offered by EditModeSwitchButton
23     // to correct this issue and still have the button do the right thing even if mouse is not involved
24     // in invoking the button.
25     //
26     // This class is associated with every instance of EditModeSwitchButton using a setter in the
27     // EditModeSwitchButton style:
28     //
29     //   &lt;Style TargetType="{x:Type PropertyEditing:EditModeSwitchButton}" BasedOn="{StaticResource {x:Type Button}}"&gt;
30     //     ...
31     //     &lt;Setter Property="Internal:EditModeSwitchButtonKeyboardFix.ApplyFix" Value="True" /&gt;
32     // </summary>
33
34     class EditModeSwitchButtonKeyboardFix 
35     {
36
37         // <summary>
38         // Property used to correct a problem with EditModeSwitchButton.  This property should only be
39         // applied to EditModeSwitchButton class instances.
40         // </summary>
41         public static readonly DependencyProperty ApplyFixProperty = DependencyProperty.RegisterAttached(
42             "ApplyFix",
43             typeof(bool),
44             typeof(EditModeSwitchButtonKeyboardFix),
45             new PropertyMetadata(false, new PropertyChangedCallback(OnApplyFixPropertyChanged)));
46
47         private bool _clickInitiatedByMouse;
48
49         private EditModeSwitchButtonKeyboardFix(EditModeSwitchButton button) 
50         {
51             button.Click += new RoutedEventHandler(OnEditModeSwitchButtonClick);
52             button.PreviewMouseLeftButtonUp += new MouseButtonEventHandler(OnEditModeSwitchButtonPreviewMouseLeftButtonUp);
53         }
54
55         // <summary>
56         // Gets the value of ApplyFix property from the specified DependencyObject.
57         // </summary>
58         // <param name="obj"></param>
59         // <returns></returns>
60         public static bool GetApplyFix(DependencyObject obj) 
61         {
62             if (obj == null)
63             {
64                 throw FxTrace.Exception.ArgumentNull("obj");
65             }
66
67             return (bool)obj.GetValue(ApplyFixProperty);
68         }
69
70         // <summary>
71         // Sets the value of ApplyFix property onto the specified DependencyObject.  Only
72         // instances of EditModeSwitchButton classes should be used as the targets of this property.
73         // </summary>
74         // <param name="obj"></param>
75         // <param name="value"></param>
76         public static void SetApplyFix(DependencyObject obj, bool value) 
77         {
78             if (obj == null)
79             {
80                 throw FxTrace.Exception.ArgumentNull("obj");
81             }
82
83             obj.SetValue(ApplyFixProperty, value);
84         }
85
86         [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults")]
87         private static void OnApplyFixPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) 
88         {
89             EditModeSwitchButton button = obj as EditModeSwitchButton;
90             if (button == null) 
91             {
92                 Debug.Fail("EditModeSwitchButtonKeyboardFix.ApplyFix fix can only be applied to EditModeSwitchButton instances.");
93                 return;
94             }
95             if (object.Equals(e.NewValue, true)) 
96             {
97                 // Instantiating this class will make itself hook into EditModeSwitchButton's events,
98                 // hence not be chewed up by garbage collector
99                 new EditModeSwitchButtonKeyboardFix(button);
100             }
101         }
102
103         private void OnEditModeSwitchButtonPreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e) 
104         {
105             _clickInitiatedByMouse = true;
106
107             ((DispatcherObject)sender).Dispatcher.BeginInvoke(DispatcherPriority.Input, new MethodInvoker(delegate() 
108             {
109                 _clickInitiatedByMouse = false;
110             }));
111         }
112
113         private void OnEditModeSwitchButtonClick(object sender, RoutedEventArgs e) 
114         {
115             if (_clickInitiatedByMouse)
116             {
117                 return;
118             }
119
120             EditModeSwitchButton button = e.OriginalSource as EditModeSwitchButton;
121             Fx.Assert(button != null, "Expected to see the EditModeSwitchButton at this point.");
122             if (button == null)
123             {
124                 return;
125             }
126
127             // At this point the click was initiated using the Invoke AutomationPeer pattern or
128             // by using the keyboard.  So, make sure that the EditModeSwitchButton.OnMouseDown
129             // button still executes.
130             // Invoke the appropriate command
131             switch (button.TargetEditMode) 
132             {
133                 case PropertyContainerEditMode.Inline:
134                     PropertyValueEditorCommands.ShowInlineEditor.Execute(null, button);
135                     break;
136                 case PropertyContainerEditMode.ExtendedPopup:
137                     PropertyValueEditorCommands.ShowExtendedPopupEditor.Execute(null, button);
138                     break;
139                 case PropertyContainerEditMode.ExtendedPinned:
140                     PropertyValueEditorCommands.ShowExtendedPinnedEditor.Execute(null, button);
141                     break;
142                 case PropertyContainerEditMode.Dialog:
143                     PropertyValueEditorCommands.ShowDialogEditor.Execute(null, button);
144                     break;
145                 default:
146                     Debug.Fail(string.Format(
147                         CultureInfo.CurrentCulture,
148                         "EditModeSwitchButtonKeyboardFix does not yet support PropertyContainerEditMode '{0}'.",
149                         button.TargetEditMode.ToString()));
150                     break;
151             }
152         }
153         private delegate void MethodInvoker();
154     }
155 }