如何处理资源字典,以免它们创建不必要的对象

How to deal with Resource Dictionaries, so they don't create unnecessary objects

我将一些常用的资源移到了 ResourceDictionary,例如

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <Style x:Key="SaveButtonStyle" TargetType="{x:Type Button}">
    <Setter Property="IsDefault" Value="True" />
    <Setter Property="IsCancel" Value="False" />
    <Setter Property="ToolTip" Value="Close and save any changes you have made." />
  </Style>
  <Style x:Key="CloseButtonStyle" BasedOn="{StaticResource XSaveCloseButtonStyle}" TargetType="{x:Type Button}">
    <Setter Property="IsDefault" Value="False" />
    <Setter Property="IsCancel" Value="True" />
    <Setter Property="ToolTip" Value="Close window." />
  </Style>
 </ResourceDictionary>

原因很简单,我需要在多个地方使用相同的样式。但是我发现了一个问题,如果某个地方我只需要使用 CloseButtonStyle,我会引用这个资源字典。我认为它创建了两种样式,我做了一些测试,并通过 FindResource 方法查看了后面的代码,看看我是否会获得每种样式的实例,我确实做到了。 所以我的问题是我该如何处理呢?如果我只需要一个对象,我不想创建 2 个对象,但我也不想通过在很多地方复制和粘贴来编写这种样式。

您可以执行以下操作:

  1. 将样式存储在工作目录或资源中的文件中(一个文件对应一种样式)
  2. 创建 class(例如 ResourcesHolder),它将通过其键为您提供资源(就像 FindResource 那样)
  3. ResourcesHolder 具有 FindResource(string resourceName) 方法:
    • 在资源中搜索与 resourceName 同名的文件
    • 使用 XamlReader 和 returns
    • 对其进行解析
  4. ResourcesHolder class 包含存储解析对象的字典。要,如果任何资源已经被解析,你将从这个字典中return它:

    private Dictionary<string, object> storedObjects;
    
    public object FindResource(string resourceName)
    {
        if (storedObjects.ContainsKey(resourceName))
            return storedObjects[resourceName];
    
        else
            //search, parse and return new resource
    }
    

    因此,您可以单独加载每个资源而无需加载任何其他内容

编辑:

在调用 Initialize() 方法之前,您可以加载创建 window/usercontrol 所需的所有资源。在这种情况下,您可以将方法添加到 ResourceHolder:

    public void Load(string resourceName)
    {
        if (Application.Current.Resources.Contains(resourceName))
            return;
        else
        {
            var obj = /*load your resource here*/;
            Application.Current.Resources.Add(resourceName, obj)
        }
    }

在你的control/window中:

    public partial class TestWindow : Window
    {
        public TestWindow()
        {
            ResourceHolder.Load("SaveButtonStyle");
            ResourceHolder.Load("CloseButtonStyle");
            InitializeComponent();
        }
    }

在这种情况下,在您的 xaml 中,您可以使用 {StaticResource} 扩展程序

如果您想在 xaml 中自动执行此操作,例如 {StaticResource} 或 {DynamicResource},您将必须编写自己的标记扩展来调用 ResourceHolder 本身的 Load 或 FindResource 方法