Reputation: 35400
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.
Upvotes: 5
Views: 4577
Reputation: 101453
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.
Upvotes: 2