1 //----------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //----------------------------------------------------------------
4 namespace System.Activities.Presentation.Internal.PropertyEditing
7 using System.Diagnostics;
8 using System.Diagnostics.CodeAnalysis;
9 using System.Globalization;
11 using System.Windows.Input;
12 using System.Windows.Threading;
13 using System.Activities.Presentation.PropertyEditing;
15 using System.Activities.Presentation;
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.
26 // This class is associated with every instance of EditModeSwitchButton using a setter in the
27 // EditModeSwitchButton style:
29 // <Style TargetType="{x:Type PropertyEditing:EditModeSwitchButton}" BasedOn="{StaticResource {x:Type Button}}">
31 // <Setter Property="Internal:EditModeSwitchButtonKeyboardFix.ApplyFix" Value="True" />
34 class EditModeSwitchButtonKeyboardFix
38 // Property used to correct a problem with EditModeSwitchButton. This property should only be
39 // applied to EditModeSwitchButton class instances.
41 public static readonly DependencyProperty ApplyFixProperty = DependencyProperty.RegisterAttached(
44 typeof(EditModeSwitchButtonKeyboardFix),
45 new PropertyMetadata(false, new PropertyChangedCallback(OnApplyFixPropertyChanged)));
47 private bool _clickInitiatedByMouse;
49 private EditModeSwitchButtonKeyboardFix(EditModeSwitchButton button)
51 button.Click += new RoutedEventHandler(OnEditModeSwitchButtonClick);
52 button.PreviewMouseLeftButtonUp += new MouseButtonEventHandler(OnEditModeSwitchButtonPreviewMouseLeftButtonUp);
56 // Gets the value of ApplyFix property from the specified DependencyObject.
58 // <param name="obj"></param>
59 // <returns></returns>
60 public static bool GetApplyFix(DependencyObject obj)
64 throw FxTrace.Exception.ArgumentNull("obj");
67 return (bool)obj.GetValue(ApplyFixProperty);
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.
74 // <param name="obj"></param>
75 // <param name="value"></param>
76 public static void SetApplyFix(DependencyObject obj, bool value)
80 throw FxTrace.Exception.ArgumentNull("obj");
83 obj.SetValue(ApplyFixProperty, value);
86 [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults")]
87 private static void OnApplyFixPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
89 EditModeSwitchButton button = obj as EditModeSwitchButton;
92 Debug.Fail("EditModeSwitchButtonKeyboardFix.ApplyFix fix can only be applied to EditModeSwitchButton instances.");
95 if (object.Equals(e.NewValue, true))
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);
103 private void OnEditModeSwitchButtonPreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
105 _clickInitiatedByMouse = true;
107 ((DispatcherObject)sender).Dispatcher.BeginInvoke(DispatcherPriority.Input, new MethodInvoker(delegate()
109 _clickInitiatedByMouse = false;
113 private void OnEditModeSwitchButtonClick(object sender, RoutedEventArgs e)
115 if (_clickInitiatedByMouse)
120 EditModeSwitchButton button = e.OriginalSource as EditModeSwitchButton;
121 Fx.Assert(button != null, "Expected to see the EditModeSwitchButton at this point.");
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)
133 case PropertyContainerEditMode.Inline:
134 PropertyValueEditorCommands.ShowInlineEditor.Execute(null, button);
136 case PropertyContainerEditMode.ExtendedPopup:
137 PropertyValueEditorCommands.ShowExtendedPopupEditor.Execute(null, button);
139 case PropertyContainerEditMode.ExtendedPinned:
140 PropertyValueEditorCommands.ShowExtendedPinnedEditor.Execute(null, button);
142 case PropertyContainerEditMode.Dialog:
143 PropertyValueEditorCommands.ShowDialogEditor.Execute(null, button);
146 Debug.Fail(string.Format(
147 CultureInfo.CurrentCulture,
148 "EditModeSwitchButtonKeyboardFix does not yet support PropertyContainerEditMode '{0}'.",
149 button.TargetEditMode.ToString()));
153 private delegate void MethodInvoker();