1
+ using System ;
2
+ using System . ComponentModel ;
3
+ using System . Globalization ;
4
+ using System . Windows ;
5
+ using System . Windows . Data ;
6
+ using System . Windows . Markup ;
7
+
8
+ namespace Rubberduck . UI . UnitTesting
9
+ {
10
+
11
+ // Source: https://stackoverflow.com/a/48202247/1419315
12
+ [ MarkupExtensionReturnType ( typeof ( object ) ) ]
13
+ public class LazyBindingExtension : MarkupExtension
14
+ {
15
+ public LazyBindingExtension ( )
16
+ { }
17
+
18
+ public LazyBindingExtension ( PropertyPath path ) : this ( )
19
+ {
20
+ Path = path ;
21
+ }
22
+
23
+ #region Properties
24
+
25
+ public IValueConverter Converter { get ; set ; }
26
+ [ TypeConverter ( typeof ( CultureInfoIetfLanguageTagConverter ) ) ]
27
+ public CultureInfo ConverterCulture { get ; set ; }
28
+ public object ConverterParameter { get ; set ; }
29
+ public string ElementName { get ; set ; }
30
+ [ ConstructorArgument ( "path" ) ]
31
+ public PropertyPath Path { get ; set ; }
32
+ public RelativeSource RelativeSource { get ; set ; }
33
+ public object Source { get ; set ; }
34
+ public UpdateSourceTrigger UpdateSourceTrigger { get ; set ; }
35
+ public bool ValidatesOnDataErrors { get ; set ; }
36
+ public bool ValidatesOnExceptions { get ; set ; }
37
+ public bool ValidatesOnNotifyDataErrors { get ; set ; }
38
+
39
+ private Binding binding ;
40
+ private UIElement bindingTarget ;
41
+ private DependencyProperty bindingTargetProperty ;
42
+
43
+ #endregion
44
+
45
+ #region Init
46
+
47
+ public override object ProvideValue ( IServiceProvider serviceProvider )
48
+ {
49
+ var valueProvider = serviceProvider . GetService ( typeof ( IProvideValueTarget ) ) as IProvideValueTarget ;
50
+ if ( valueProvider == null )
51
+ {
52
+ return null ;
53
+ }
54
+ bindingTarget = valueProvider . TargetObject as UIElement ;
55
+
56
+ if ( bindingTarget == null )
57
+ {
58
+ throw new NotSupportedException ( $ "The target must be a UIElement, '{ valueProvider . TargetObject } ' is not valid.") ;
59
+ }
60
+
61
+ bindingTargetProperty = valueProvider . TargetProperty as DependencyProperty ;
62
+
63
+ if ( bindingTargetProperty == null )
64
+ {
65
+ throw new NotSupportedException ( $ "The target property must be a DependencyProperty, '{ valueProvider . TargetProperty } ' is not valid.") ;
66
+ }
67
+
68
+ binding = new Binding
69
+ {
70
+ Path = Path ,
71
+ Converter = Converter ,
72
+ ConverterCulture = ConverterCulture ,
73
+ ConverterParameter = ConverterParameter
74
+ } ;
75
+
76
+ if ( ElementName != null )
77
+ {
78
+ binding . ElementName = ElementName ;
79
+ }
80
+
81
+ if ( RelativeSource != null )
82
+ {
83
+ binding . RelativeSource = RelativeSource ;
84
+ }
85
+
86
+ if ( Source != null )
87
+ {
88
+ binding . Source = Source ;
89
+ }
90
+
91
+ binding . UpdateSourceTrigger = UpdateSourceTrigger ;
92
+ binding . ValidatesOnDataErrors = ValidatesOnDataErrors ;
93
+ binding . ValidatesOnExceptions = ValidatesOnExceptions ;
94
+ binding . ValidatesOnNotifyDataErrors = ValidatesOnNotifyDataErrors ;
95
+
96
+ return SetBinding ( ) ;
97
+ }
98
+
99
+
100
+ public object SetBinding ( )
101
+ {
102
+ bindingTarget . IsVisibleChanged += UiElement_IsVisibleChanged ;
103
+
104
+ UpdateBinding ( ) ;
105
+
106
+ return bindingTarget . GetValue ( bindingTargetProperty ) ;
107
+ }
108
+
109
+ #endregion
110
+
111
+ #region Event Handlers
112
+
113
+ private void UiElement_IsVisibleChanged ( object sender , DependencyPropertyChangedEventArgs e )
114
+ {
115
+ UpdateBinding ( ) ;
116
+ }
117
+
118
+ #endregion
119
+
120
+ #region Update Binding
121
+
122
+ private void UpdateBinding ( )
123
+ {
124
+ if ( bindingTarget . IsVisible && ! IsBindingActive ( ) )
125
+ ApplyBinding ( ) ;
126
+ else if ( ! bindingTarget . IsVisible )
127
+ ClearBinding ( ) ;
128
+ }
129
+
130
+ private bool IsBindingActive ( )
131
+ {
132
+ return BindingOperations . GetBinding ( bindingTarget , bindingTargetProperty ) != null ;
133
+ }
134
+
135
+ private void ApplyBinding ( )
136
+ {
137
+ if ( ! IsBindingActive ( ) )
138
+ BindingOperations . SetBinding ( bindingTarget , bindingTargetProperty , binding ) ;
139
+ }
140
+
141
+ private void ClearBinding ( )
142
+ {
143
+ if ( IsBindingActive ( ) )
144
+ BindingOperations . ClearBinding ( bindingTarget , bindingTargetProperty ) ;
145
+ }
146
+
147
+ #endregion
148
+ }
149
+ }
0 commit comments