如何向 UserControl 添加更多资源

How to add more resources to a UserControl

我们能否在使用时向 UserControl 添加新资源,而不清除 UserControl 自己定义的资源?

例如,这里是 UserControl:

<UserControl x:Class="MyControl">
  <UserControl.Resources>
    <!--Resource1-->
    <!--Resource2-->
  </UserControl.Resources>
</UserControl>

我在MainWindow中使用这个控件:

<MainWindow>
  <local:MyControl>
    <local:MyControl.Resources>
      <!--Resource3-->
    </local:MyControl.Resources>
  </local:MyControl>
</MainWindow>

这样做会清除 Resource1 和 Resource2,我只剩下 Resource3。 <ResourceDictionary.MergedDictionaries> 我也试过了,也是一样的效果。我正在寻找 Resource3 add 到现有资源列表的方法。

据我所知,没有内置的可能性可以做到这一点。但是您可以通过代码或附加 属性 来做到这一点。例如,让我们定义这样的 属性:

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);
    }
}

它会做的是获取资源字典并将所有值从它复制到目标控件的资源字典(覆盖现有资源的值)。用法是:

<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}"/>

请注意,为了帮助您解决您在评论中链接的另一个问题 - 您需要使用 DynamicResource 扩展名的资源,而不是 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>

如果我将带有附加 属性 的上述方法应用到此 UserControl - 里面的文本将变成黄色(以前是红色),因为 Brushforeground被覆盖但是 Styletest 保持不变,我使用 DynamicResource。如果我改用 StaticResource - 资源字典中的资源仍会更改,但控件不会反映该更改,因为使用 StaticResource 它不会监视资源中的更改。