【问题标题】:Multiple instances of the same ResourceDictionary同一个 ResourceDictionary 的多个实例
【发布时间】:2017-10-18 11:01:13
【问题描述】:

我发现this post 在网络上提高了ResourceDictionaries 的性能,但问题是它已经很老了(2011 年)。我正在考虑实现这样的东西,但我想知道微软是否没有在.NET Framework 的最新版本中修复这个问题。关于这个话题我有几个问题,希望有人能回答一下:

  1. .NET Framework 4.6.1 是否仍然通过创建多个实例来管理 ResourceDictionaries,每次将它们分配给一个控件时一个实例?
  2. 当我在我的ResourceDictionary 中调用"ButtonStyles" 在名为"StylesAssembly" 的程序集中有样式"CustomButtonStyle" 时,这甚至是一个问题,然后在应用程序的App.xaml 中引用它,它有20 个@987654330 @ 和 CustomButtonStyle 分配给他们?
  3. 我理解正确吗,在上述情况下,"ButtonStyles"ResourceDictionary 的实例将有 20 个?

【问题讨论】:

  • 我想这很容易测试,但我很难理解确切的场景。你的意思是另一个带有资源字典的程序集还是什么?
  • @mm8 我已经编辑了第 1 点以便更容易理解,感谢指出我的错误
  • @Sinatr 问题是我不知道如何测试它,因为ResourceDictionary 后面没有代码,所以我不能在那里设置断点。场景是:StyleAssembly 是一个ClassLibrary,其中有ResourceDictionary,称为ButtonStyles,其中有CustomButtonStyle。我的应用程序引用 StyleAssembly 并将其合并到 App.xaml 中,我的 MainWindow 有 20 个 Buttons 使用样式 CustomButtonStyle。它会让我的应用创建 20 个 ButtonStyles 实例吗?
  • 我用@mm8方法测试过这种场景,没有问题。仅创建一个实例。发生多次加载的一种明显情况是直接在例如 <ResourceDictionary Source="pack://application:,,,/ClassLibrary;component/ResourceDictionary.xaml" /> 中写入UserControl.Resources。这确实会为此类用户控件的每个实例创建一个新的资源字典实例。相反,您必须定义一次per application

标签: c# wpf xaml resourcedictionary


【解决方案1】:

感谢@mm8 发布您的答案。 100% 正确,我只想发表我自己的答案,因为我发现了一些有趣的东西,可能对其他人有用。

答案是:ResourceDictionary 实例如果在应用程序中被引用,将只创建一次(无论许多控件使用它的样式),但每次在另一个 ResourceDictionary 中引用它时都会再次实例化它。在应用程序中使用。


为了给你举个例子,假设我们有以下结构:

- StylesAssembly.dll
  - ButtonResourceDictionary.xaml
  - CustomButtonResourceDictionary.xaml

- Application.exe
  - App.xaml
  - MainWindow.xaml

ButtonResourceDictionary.xaml 有以下代码:

<Style x:Key="DefaultButtonStyle" TargetType="{x:Type Button}">
    <!-- Some setters -->
</Style>

CustomButtonResourceDictionary.xaml 有以下代码,使用ButtonResourceDictionary.xaml

<ResourceDictionary.MergedDictionaries>
    <ResourceDictionary Source="ButtonResourceDictionary.xaml" />
</ResourceDictionary.MergedDictionaries>

<Style x:Key="CustomButtonStyle" TargetType="{x:Type Button}" BasedOn="{StaticResource DefaultButtonStyle}">
    <!-- Some setters -->
</Style>

Application.exe 有一个对StylesAssembly.dll 的引用,并且在 App.xaml 中有如下代码:

<Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="pack://application:,,,/StylesAssembly;component/ButtonResourceDictionary.xaml" />
            <ResourceDictionary Source="pack://application:,,,/StylesAssembly;component/CustomButtonResourceDictionary.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Application.Resources>

现在,如果我们的 MainWindow.xaml 中有这样的内容,ButtonResourceDictionary.xaml 将只有 一个实例

<StackPanel>
    <Button Style="{StaticResource DefaultButtonStyle}" />
    <Button Style="{StaticResource DefaultButtonStyle}" />
    <Button Style="{StaticResource DefaultButtonStyle}" />
    <Button Style="{StaticResource DefaultButtonStyle}" />
    <Button Style="{StaticResource DefaultButtonStyle}" />
</StackPanel>

但如果我们的 MainWindow.xaml 中有类似的内容,CustomButtonResourceDictionary.xaml 将有一个实例,但ButtonResourceDictionary.xaml 将有两个实例

<StackPanel>
    <Button Style="{StaticResource DefaultButtonStyle}" />
    <Button Style="{StaticResource DefaultButtonStyle}" />
    <Button Style="{StaticResource CustomButtonStyle}" />
    <Button Style="{StaticResource CustomButtonStyle}" />
    <Button Style="{StaticResource CustomButtonStyle}" />
</StackPanel>

这是因为前两个 Buttons 使用来自 ButtonResourceDictionary.xaml 的样式 DefaultButtonStyle,但另外三个 Buttons 使用来自 CustomButtonResourceDictionary.xaml 的样式 CustomButtonStyle,它在其代码中合并了 ButtonResourceDictionary.xaml

【讨论】:

  • 这是预期的行为。如果不创建它的实例,如何解决合并的字典?
  • 我不反对。很难找到(根据我今天的经历),所以我决定将所有内容集中在一个地方并将其发布在这里。也许它会在未来帮助某人。
【解决方案2】:

我是否理解正确,在上述情况下,将有 20 个“ButtonStyles”ResourceDictionary 实例?

没有。只有一个。

当我在名为“StylesAssembly”的程序集中使用名为“ButtonStyles”的ResourceDictionary 中的样式“CustomButtonStyle”,然后在应用程序的App.xaml 中引用该样式时,这是否甚至是一个问题,该应用程序有 20 个按钮CustomButtonStyle 分配给他们?

如果您将ResourceDictionary 合并到您的App.xaml 中并在应用程序的视图中创建20 个Button 元素,则仍然只会创建一个ResourceDictionary 类的实例。

您可以通过将代码隐藏类添加到ResourceDictionary 来自己确认这一点:

Is it possible to set code behind a resource dictionary in WPF for event handling?

...并在构造函数中放置一个断点。

在创建的ResourceDictionary 中也将只定义一个Style 实例。

【讨论】:

  • 谢谢,我不知道我可以在ResourceDictionary 中添加类后面的代码。我想自己检查一下,如果有效,我会将其标记为答案。
  • @mm8,以及来自here 的语句“每次控件引用 ResourceDictionary XAML 创建它的新实例” 怎么样?我不是说你错了,但我怀疑他们使用了你测试过的另一种场景。
  • 问题是这篇文章是2011年的。这就是我问这个问题的原因。它可能已经过时了
  • @mm8 谢谢,它就像你说的那样工作。我也允许自己为我的问题添加另一个答案,因为我发现了一个有趣的细节,可能对其他人有所帮助。
【解决方案3】:

我最近一直在和朋友一起研究另一种解决方案,我想分享一下。目标是能够在任何地方使用 ResourceDictionaries 并以任何必要的方式合并它们,但仍然只将它们实例化一次并且不会破坏 VS 设计器和 Blend 等。

说明:
1. 根据需要在 xaml 中使用合并的 ResourceDictionaries。
2.引用nuget包Sundew.Xaml.OptimizationsSundew.Xaml.Optimizer
3. 在项目根目录下添加 sxo-settings.json 并启用 ResourceDictionaryCachingOptimizer
4. 构建
构建将使用缓存/共享的 ResourceDictionary,但设计器也可以工作,因为他们只看到正常的 ResourceDictionary。

更多详情请见:https://github.com/hugener/Sundew.Xaml.Optimizations
还有一个示例:https://github.com/hugener/Sundew.Xaml.Optimizer.Sample

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-06-18
    • 2016-04-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-26
    • 2020-07-24
    • 2018-11-21
    相关资源
    最近更新 更多