1
+ using System ;
2
+ using System . Reflection ;
3
+ using System . Windows ;
4
+ using System . Windows . Input ;
5
+ using System . Windows . Threading ;
6
+
7
+ namespace ControlzEx
8
+ {
9
+ /// <summary>
10
+ /// Helper class for a common focusing problem.
11
+ /// The focus itself isn't the problem. If we use the common focusing methods the control get the focus
12
+ /// but it doesn't get the focus visual style.
13
+ /// The KeyboardNavigation class handles the visual style only if the control get the focus from a keyboard
14
+ /// device or if the SystemParameters.KeyboardCues is true.
15
+ /// </summary>
16
+ public sealed class KeyboardNavigationEx
17
+ {
18
+ private static KeyboardNavigationEx _instance ;
19
+ //internal static bool AlwaysShowFocusVisual
20
+ private readonly PropertyInfo _alwaysShowFocusVisual ;
21
+ //internal static void ShowFocusVisual()
22
+ private readonly MethodInfo _showFocusVisual ;
23
+
24
+ // Explicit static constructor to tell C# compiler
25
+ // not to mark type as beforefieldinit
26
+ static KeyboardNavigationEx ( )
27
+ {
28
+ }
29
+
30
+ private KeyboardNavigationEx ( )
31
+ {
32
+ var type = typeof ( KeyboardNavigation ) ;
33
+ _alwaysShowFocusVisual = type . GetProperty ( "AlwaysShowFocusVisual" , BindingFlags . NonPublic | BindingFlags . Static ) ;
34
+ _showFocusVisual = type . GetMethod ( "ShowFocusVisual" , BindingFlags . NonPublic | BindingFlags . Static ) ;
35
+ }
36
+
37
+ /// <summary>
38
+ /// Gets the KeyboardNavigationEx singleton instance.
39
+ /// </summary>
40
+ internal static KeyboardNavigationEx Instance => _instance ?? ( _instance = new KeyboardNavigationEx ( ) ) ;
41
+
42
+ /// <summary>
43
+ /// Shows the focus visual of the current focused UI element.
44
+ /// Works only together with AlwaysShowFocusVisual property.
45
+ /// </summary>
46
+ internal void ShowFocusVisualInternal ( )
47
+ {
48
+ _showFocusVisual . Invoke ( null , null ) ;
49
+ }
50
+
51
+ internal bool AlwaysShowFocusVisualInternal
52
+ {
53
+ get { return ( bool ) _alwaysShowFocusVisual . GetValue ( null , null ) ; }
54
+ set { _alwaysShowFocusVisual . SetValue ( null , value , null ) ; }
55
+ }
56
+
57
+ /// <summary>
58
+ /// Focuses the specified element and shows the focus visual style.
59
+ /// </summary>
60
+ /// <param name="element">The element which will be focused.</param>
61
+ public static void Focus ( UIElement element )
62
+ {
63
+ element ? . Dispatcher . BeginInvoke ( DispatcherPriority . Background , new Action ( ( ) =>
64
+ {
65
+ var keybHack = KeyboardNavigationEx . Instance ;
66
+ var alwaysShowFocusVisual = keybHack . AlwaysShowFocusVisualInternal ;
67
+ keybHack . AlwaysShowFocusVisualInternal = true ;
68
+ try
69
+ {
70
+ Keyboard . Focus ( element ) ;
71
+ keybHack . ShowFocusVisualInternal ( ) ;
72
+ }
73
+ finally
74
+ {
75
+ keybHack . AlwaysShowFocusVisualInternal = alwaysShowFocusVisual ;
76
+ }
77
+ } ) ) ;
78
+ }
79
+
80
+ /// <summary>
81
+ /// Attached DependencyProperty for setting AlwaysShowFocusVisual for a UI element.
82
+ /// </summary>
83
+ public static readonly DependencyProperty AlwaysShowFocusVisualProperty
84
+ = DependencyProperty . RegisterAttached ( "AlwaysShowFocusVisual" ,
85
+ typeof ( bool ) ,
86
+ typeof ( KeyboardNavigationEx ) ,
87
+ new FrameworkPropertyMetadata ( default ( bool ) , AlwaysShowFocusVisualPropertyChangedCallback ) ) ;
88
+
89
+ private static void AlwaysShowFocusVisualPropertyChangedCallback ( DependencyObject dependencyObject , DependencyPropertyChangedEventArgs args )
90
+ {
91
+ var fe = dependencyObject as UIElement ;
92
+ if ( fe != null && args . NewValue != args . OldValue )
93
+ {
94
+ fe . GotFocus -= FrameworkElementGotFocus ;
95
+ if ( ( bool ) args . NewValue )
96
+ {
97
+ fe . GotFocus += FrameworkElementGotFocus ;
98
+ }
99
+ }
100
+ }
101
+
102
+ private static void FrameworkElementGotFocus ( object sender , RoutedEventArgs e )
103
+ {
104
+ KeyboardNavigationEx . Focus ( sender as UIElement ) ;
105
+ }
106
+
107
+ /// <summary>
108
+ /// Gets a the value which indicates if the UI element always show the focus visual style.
109
+ /// </summary>
110
+ [ AttachedPropertyBrowsableForType ( typeof ( UIElement ) ) ]
111
+ public static bool GetAlwaysShowFocusVisual ( UIElement element )
112
+ {
113
+ return ( bool ) element . GetValue ( AlwaysShowFocusVisualProperty ) ;
114
+ }
115
+
116
+ /// <summary>
117
+ /// Sets a the value which indicates if the UI element always show the focus visual style.
118
+ /// </summary>
119
+ public static void SetAlwaysShowFocusVisual ( UIElement element , bool value )
120
+ {
121
+ element . SetValue ( AlwaysShowFocusVisualProperty , value ) ;
122
+ }
123
+ }
124
+ }
0 commit comments