@@ -12,6 +12,13 @@ namespace Coder.Desktop.App.Converters;
1212// DependencyPropertyGenerator since it doesn't seem to work properly with
1313// generics.
1414
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>
1522public class DependencyObjectSelectorItem < TK , TV > : DependencyObject
1623 where TK : IEquatable < TK >
1724{
@@ -40,6 +47,14 @@ public TV? Value
4047 }
4148}
4249
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>
4358[ ContentProperty ( Name = nameof ( References ) ) ]
4459public class DependencyObjectSelector < TK , TV > : DependencyObject
4560 where TK : IEquatable < TK >
@@ -54,7 +69,7 @@ public class DependencyObjectSelector<TK, TV> : DependencyObject
5469 DependencyProperty . Register ( nameof ( SelectedKey ) ,
5570 typeof ( TK ? ) ,
5671 typeof ( DependencyObjectSelector < TK , TV > ) ,
57- new PropertyMetadata ( null , SelectedPropertyChanged ) ) ;
72+ new PropertyMetadata ( null , SelectedKeyPropertyChanged ) ) ;
5873
5974 public static readonly DependencyProperty SelectedObjectProperty =
6075 DependencyProperty . Register ( nameof ( SelectedObject ) ,
@@ -80,12 +95,22 @@ public DependencyObjectCollection? References
8095 }
8196 }
8297
98+ /// <summary>
99+ /// The key of the selected item. This should be bound to a property on
100+ /// the model.
101+ /// </summary>
83102 public TK ? SelectedKey
84103 {
85104 get => ( TK ? ) GetValue ( SelectedKeyProperty ) ;
86105 set => SetValue ( SelectedKeyProperty , value ) ;
87106 }
88107
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>
89114 public TV ? SelectedObject
90115 {
91116 get => ( TV ? ) GetValue ( SelectedObjectProperty ) ;
@@ -97,15 +122,12 @@ public DependencyObjectSelector()
97122 References = [ ] ;
98123 }
99124
100- private void OnVectorChangedReferences ( IObservableVector < DependencyObject > sender , IVectorChangedEventArgs args )
101- {
102- UpdateSelectedObject ( ) ;
103- }
104-
105125 private void UpdateSelectedObject ( )
106126 {
107127 if ( References != null )
108128 {
129+ // Look for a matching item a matching key, or fallback to the null
130+ // key.
109131 var references = References . OfType < DependencyObjectSelectorItem < TK , TV > > ( ) . ToArray ( ) ;
110132 var item = references
111133 . FirstOrDefault ( i =>
@@ -114,6 +136,9 @@ private void UpdateSelectedObject()
114136 ?? references . FirstOrDefault ( i => i . Key == null ) ;
115137 if ( item is not null )
116138 {
139+ // Bind the SelectedObject property to the reference's Value.
140+ // If the underlying Value changes, it will propagate to the
141+ // SelectedObject.
117142 BindingOperations . SetBinding
118143 (
119144 this ,
@@ -131,6 +156,7 @@ private void UpdateSelectedObject()
131156 ClearValue ( SelectedObjectProperty ) ;
132157 }
133158
159+ // Called when the References property is replaced.
134160 private static void ReferencesPropertyChanged ( DependencyObject obj , DependencyPropertyChangedEventArgs args )
135161 {
136162 var self = obj as DependencyObjectSelector < TK , TV > ;
@@ -143,7 +169,14 @@ private static void ReferencesPropertyChanged(DependencyObject obj, DependencyPr
143169 newValue . VectorChanged += self . OnVectorChangedReferences ;
144170 }
145171
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 )
147180 {
148181 var self = obj as DependencyObjectSelector < TK , TV > ;
149182 self ? . UpdateSelectedObject ( ) ;
0 commit comments