I have a solution based on a pair of "helper" classes. At first it’s just an object container with DependencyProperty Value , which can be linked or set to {ThemeResource …} :
public class DependencyObjectReference<T> : DependencyObject where T : DependencyObject { #region Properties public T Value { get { return (T)GetValue(ValueProperty); } set { SetValue(ValueProperty, value); } } #endregion #region Static Data public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(nameof(Value), typeof(T), typeof(DependencyObjectReference<T>), new PropertyMetadata(default(T))); #endregion }
The following is the basis of the solution: a "selector" that contains a group of links and selects from them based on the index:
[ContentProperty(Name = nameof(References))] public class DependencyObjectSelector<T> : DependencyObject where T : DependencyObject { #region Constructors public DependencyObjectSelector() { References = new DependencyObjectCollection(); } #endregion #region Properties public DependencyObjectCollection References { get { return (DependencyObjectCollection)GetValue(ReferencesProperty); } set { SetValue(ReferencesProperty, value); } } public Int32 SelectedIndex { get { return (Int32)GetValue(SelectedIndexProperty); } set { SetValue(SelectedIndexProperty, value); } } public T SelectedObject { get { return (T)GetValue(SelectedObjectProperty); } set { SetValue(SelectedObjectProperty, value); } } #endregion #region Event Handlers private void Evt_OnVectorChangedReferences(IObservableVector<DependencyObject> sender, IVectorChangedEventArgs args) { UpdateSelectedObject(); } #endregion #region Private Implementation Methods private void UpdateSelectedObject() { if ( References != null && SelectedIndex >= 0 && SelectedIndex < References.Count && References[SelectedIndex] is DependencyObjectReference<T> ) { BindingOperations.SetBinding ( this, SelectedObjectProperty, new Binding { Source = References[SelectedIndex], Path = new PropertyPath(nameof(DependencyObjectReference<T>.Value)) } ); } else { ClearValue(SelectedObjectProperty); } } private void OnReferencesPropertyChanged(DependencyObjectCollection oldValue, DependencyObjectCollection newValue) { if (oldValue != null) oldValue.VectorChanged -= Evt_OnVectorChangedReferences; if (newValue != null) newValue.VectorChanged += Evt_OnVectorChangedReferences; } private static void ReferencesPropertyChanged(DependencyObject dobj, DependencyPropertyChangedEventArgs args) { DependencyObjectSelector<T> _this = (DependencyObjectSelector<T>)dobj; _this.OnReferencesPropertyChanged(args.OldValue as DependencyObjectCollection, args.NewValue as DependencyObjectCollection); } private static void SelectedIndexPropertyChanged(DependencyObject dobj, DependencyPropertyChangedEventArgs args) { DependencyObjectSelector<T> _this = (DependencyObjectSelector<T>)dobj; _this.UpdateSelectedObject(); } #endregion #region Static Data public static readonly DependencyProperty ReferencesProperty = DependencyProperty.Register(nameof(References), typeof(DependencyObjectCollection), typeof(DependencyObjectSelector<T>), new PropertyMetadata(null, ReferencesPropertyChanged)); public static readonly DependencyProperty SelectedIndexProperty = DependencyProperty.Register(nameof(SelectedIndex), typeof(Int32), typeof(DependencyObjectSelector<T>), new PropertyMetadata(-1, SelectedIndexPropertyChanged)); public static readonly DependencyProperty SelectedObjectProperty = DependencyProperty.Register(nameof(SelectedObject), typeof(T), typeof(DependencyObjectSelector<T>), new PropertyMetadata(default(T))); #endregion }
As you see, this class contains a collection of links and associates its SelectedObject property with the Value corresponding link. This binding is updated when the SelectedIndex changes and when the link collection itself changes.
Obviously, these classes cannot be used in XAML, because they are parameterized by type T (which should be derived from DependencyObject ). However, theirs is just a subclass:
public sealed class BrushReference : DependencyObjectReference<Brush> { }
public sealed class BrushSelector : DependencyObjectSelector<Brush> { }
The trick is to put the BrushSelector in some available ResourceDictionary (like your Resources Page ) and then bind it to the SelectedObject property:
<Page.Resources> <mynamespace:BrushSelector x:Key="MyBrushSelector" SelectedIndex="{x:Bind Path=MyViewModel.MyBrushIndex, Mode=OneWay}"> <mynamespace:BrushReference Value="{ThemeResource SystemControlForegroundAccentColor}"/> <mynamespace:BrushReference Value="{ThemeResource SystemControlForegroundBaseHighBrush}"/> <mynamespace:BrushReference Value="Red"/> <mynamespace:BrushReference Value="Wheat"/> </mynamespace:BrushSelector> </Page.Resources> <TextBlock Text="..." Foreground="{Binding Source={StaticResource MyBrushSelector}, Path=SelectedObject}" />
Note that there is no need to specify <DependencyObjectCollection> when defining BrushSelector in XAML due to the [ContentProperty] attribute in the selector class.
A few other comments - firstly, I would prefer SelectedObject to be a read-only DependencyProperty , as it should never be set by markup or code outside the selector, but UWP does not yet support this. Secondly, the References property must be of the DependencyObjectCollection type and the property itself must be DependencyProperty otherwise the theme changes are not propagated correctly. Finally, you can even use your own theme resources, and if your application does not indicate an explicit theme, when you change the theme in the Windows control panel (for example, “Light” → “Dark” or vice versa), these colors will be updated as Well.