Can we add new resources to a UserControl
at the point of usage, without wiping out the resources that UserControl
has defined itself?
So for exmaple, here is a UserControl
:
<UserControl x:Class="MyControl">
<UserControl.Resources>
<!--Resource1-->
<!--Resource2-->
</UserControl.Resources>
</UserControl>
I use this control in the MainWindow
:
<MainWindow>
<local:MyControl>
<local:MyControl.Resources>
<!--Resource3-->
</local:MyControl.Resources>
</local:MyControl>
</MainWindow>
Doing this wipes out Resource1 and Resource2 and I'm left with Resource3 only. I have tried <ResourceDictionary.MergedDictionaries>
too, that also has the same effect. I'm looking for a way for Resource3 to add to the existing resources list.
There is no built-in possibility to do that, as far as I know. But you can do that either via code, or with attached property. For example, let's define such property:
public static class ResourceExtensions {
public static readonly DependencyProperty AdditionalResourcesProperty = DependencyProperty.RegisterAttached(
"AdditionalResources", typeof(ResourceDictionary), typeof(ResourceExtensions), new PropertyMetadata(null, OnAdditionalResourcesChanged));
private static void OnAdditionalResourcesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
var fe = d as FrameworkElement;
if (fe == null)
throw new Exception("Cannot add resources to type " + d.GetType());
if (fe.Resources == null)
fe.Resources = new ResourceDictionary();
var dict = e.NewValue as ResourceDictionary;
if (dict != null) {
foreach (DictionaryEntry resource in dict) {
fe.Resources[resource.Key] = resource.Value;
}
}
}
public static void SetAdditionalResources(DependencyObject element, ResourceDictionary value) {
element.SetValue(AdditionalResourcesProperty, value);
}
public static ResourceDictionary GetAdditionalResources(DependencyObject element) {
return (ResourceDictionary) element.GetValue(AdditionalResourcesProperty);
}
}
What it will do is take resource dictionary and copy all values from it to the resource dictionary of target control (overriding values of existing resources). Usage is:
<Window.Resources>
<ResourceDictionary>
<!-- This is resource dictionary to merge with target -->
<ResourceDictionary x:Key="overrideResources">
<Brush x:Key="foreground">Yellow</Brush>
</ResourceDictionary>
</ResourceDictionary>
</Window.Resources>
<wpfApplication1:UserControl1 wpfApplication1:ResourceExtensions.AdditionalResources="{StaticResource overrideResources}"/>
Note that for it to help with your another question you linked in comments - you need to use resources using DynamicResource
extension, not StaticResource
:
<UserControl.Resources>
<Brush x:Key="foreground">Red</Brush>
<Style x:Key="test" TargetType="TextBlock">
<!-- Note DynamicResource here -->
<Setter Property="Foreground" Value="{DynamicResource foreground}" />
</Style>
</UserControl.Resources>
<StackPanel>
<TextBlock Text="test" FontSize="12" Style="{StaticResource test}" />
</StackPanel>
If I apply the above method with attached property to this UserControl
- text inside it will become yellow (was red), because Brush
with key foreground
was overriden but Style
with key test
was left intact, and I used DynamicResource
. If I used StaticResource
instead - resources in resource dictionary will still change, but control will not reflect that change, because with StaticResource
it does not watch for changes in the resource.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With