@@ -12,6 +12,13 @@ namespace Coder.Desktop.App.Converters;
12
12
// DependencyPropertyGenerator since it doesn't seem to work properly with
13
13
// generics.
14
14
15
+ /// <summary>
16
+ /// An item in a DependencyObjectSelector. Each item has a key and a value.
17
+ /// The default item in a DependencyObjectSelector will be the only item
18
+ /// with a null key.
19
+ /// </summary>
20
+ /// <typeparam name="TK">Key type</typeparam>
21
+ /// <typeparam name="TV">Value type</typeparam>
15
22
public class DependencyObjectSelectorItem < TK , TV > : DependencyObject
16
23
where TK : IEquatable < TK >
17
24
{
@@ -40,6 +47,14 @@ public TV? Value
40
47
}
41
48
}
42
49
50
+ /// <summary>
51
+ /// Allows selecting between multiple value references based on a selected
52
+ /// key. This allows for dynamic mapping of model values to other objects.
53
+ /// The main use case is for selecting between other bound values, which
54
+ /// you cannot do with a simple ValueConverter.
55
+ /// </summary>
56
+ /// <typeparam name="TK">Key type</typeparam>
57
+ /// <typeparam name="TV">Value type</typeparam>
43
58
[ ContentProperty ( Name = nameof ( References ) ) ]
44
59
public class DependencyObjectSelector < TK , TV > : DependencyObject
45
60
where TK : IEquatable < TK >
@@ -54,7 +69,7 @@ public class DependencyObjectSelector<TK, TV> : DependencyObject
54
69
DependencyProperty . Register ( nameof ( SelectedKey ) ,
55
70
typeof ( TK ? ) ,
56
71
typeof ( DependencyObjectSelector < TK , TV > ) ,
57
- new PropertyMetadata ( null , SelectedPropertyChanged ) ) ;
72
+ new PropertyMetadata ( null , SelectedKeyPropertyChanged ) ) ;
58
73
59
74
public static readonly DependencyProperty SelectedObjectProperty =
60
75
DependencyProperty . Register ( nameof ( SelectedObject ) ,
@@ -80,12 +95,22 @@ public DependencyObjectCollection? References
80
95
}
81
96
}
82
97
98
+ /// <summary>
99
+ /// The key of the selected item. This should be bound to a property on
100
+ /// the model.
101
+ /// </summary>
83
102
public TK ? SelectedKey
84
103
{
85
104
get => ( TK ? ) GetValue ( SelectedKeyProperty ) ;
86
105
set => SetValue ( SelectedKeyProperty , value ) ;
87
106
}
88
107
108
+ /// <summary>
109
+ /// The selected object. This can be read from to get the matching
110
+ /// object for the selected key. If the selected key doesn't match any
111
+ /// object, this will be the value of the null key. If there is no null
112
+ /// key, this will be null.
113
+ /// </summary>
89
114
public TV ? SelectedObject
90
115
{
91
116
get => ( TV ? ) GetValue ( SelectedObjectProperty ) ;
@@ -97,15 +122,12 @@ public DependencyObjectSelector()
97
122
References = [ ] ;
98
123
}
99
124
100
- private void OnVectorChangedReferences ( IObservableVector < DependencyObject > sender , IVectorChangedEventArgs args )
101
- {
102
- UpdateSelectedObject ( ) ;
103
- }
104
-
105
125
private void UpdateSelectedObject ( )
106
126
{
107
127
if ( References != null )
108
128
{
129
+ // Look for a matching item a matching key, or fallback to the null
130
+ // key.
109
131
var references = References . OfType < DependencyObjectSelectorItem < TK , TV > > ( ) . ToArray ( ) ;
110
132
var item = references
111
133
. FirstOrDefault ( i =>
@@ -114,6 +136,9 @@ private void UpdateSelectedObject()
114
136
?? references . FirstOrDefault ( i => i . Key == null ) ;
115
137
if ( item is not null )
116
138
{
139
+ // Bind the SelectedObject property to the reference's Value.
140
+ // If the underlying Value changes, it will propagate to the
141
+ // SelectedObject.
117
142
BindingOperations . SetBinding
118
143
(
119
144
this ,
@@ -131,6 +156,7 @@ private void UpdateSelectedObject()
131
156
ClearValue ( SelectedObjectProperty ) ;
132
157
}
133
158
159
+ // Called when the References property is replaced.
134
160
private static void ReferencesPropertyChanged ( DependencyObject obj , DependencyPropertyChangedEventArgs args )
135
161
{
136
162
var self = obj as DependencyObjectSelector < TK , TV > ;
@@ -143,7 +169,14 @@ private static void ReferencesPropertyChanged(DependencyObject obj, DependencyPr
143
169
newValue . VectorChanged += self . OnVectorChangedReferences ;
144
170
}
145
171
146
- private static void SelectedPropertyChanged ( DependencyObject obj , DependencyPropertyChangedEventArgs args )
172
+ // Called when the References collection changes without being replaced.
173
+ private void OnVectorChangedReferences ( IObservableVector < DependencyObject > sender , IVectorChangedEventArgs args )
174
+ {
175
+ UpdateSelectedObject ( ) ;
176
+ }
177
+
178
+ // Called when SelectedKey changes.
179
+ private static void SelectedKeyPropertyChanged ( DependencyObject obj , DependencyPropertyChangedEventArgs args )
147
180
{
148
181
var self = obj as DependencyObjectSelector < TK , TV > ;
149
182
self ? . UpdateSelectedObject ( ) ;
0 commit comments