如何向UserControl添加更多资源

时间:2017-03-18 11:55:23

标签: wpf xaml wpf-controls resourcedictionary

我们是否可以在使用时向UserControl添加新资源,而不会消除UserControl自定义的资源?

因此,对于exmaple,这是一个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 添加到现有资源列表。

1 个答案:

答案 0 :(得分:1)

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

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 - 其中的文字将变为黄色(红色),因为Brush带有键foreground但是{{1}密钥Style保持不变,我使用了test。如果我使用DynamicResource代替 - 资源字典中的资源仍会更改,但控件不会反映该更改,因为StaticResource它不会监视资源中的更改。