Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 5ddda6f

Browse files
committedMar 24, 2025·
PR comments
1 parent b73ebe0 commit 5ddda6f

11 files changed

+699
-604
lines changed
 

‎App/App.xaml.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ public App()
4747
services.AddTransient<SignInViewModel>();
4848
services.AddTransient<SignInWindow>();
4949

50+
// FileSyncListWindow views and view models
51+
services.AddTransient<FileSyncListViewModel>();
52+
// FileSyncListMainPage is created by FileSyncListWindow.
53+
services.AddTransient<FileSyncListWindow>();
54+
5055
// TrayWindow views and view models
5156
services.AddTransient<TrayWindowLoadingPage>();
5257
services.AddTransient<TrayWindowDisconnectedViewModel>();

‎App/Converters/DependencyObjectSelector.cs

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -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>
1522
public 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))]
4459
public 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

Comments
 (0)
Please sign in to comment.