【问题标题】:What's the difference between StaticResource and DynamicResource in WPF?WPF中的StaticResource和DynamicResource有什么区别?
【发布时间】:2010-09-17 01:58:07
【问题描述】:

在 WPF 中使用画笔、模板和样式等资源时,可以将它们指定为 StaticResources

<Rectangle Fill="{StaticResource MyBrush}" />

或作为动态资源

<ItemsControl ItemTemplate="{DynamicResource MyItemTemplate}"  />

大多数时候(总是?),只有一个有效,另一个会在运行时抛出异常。但我想知道为什么:

  • 主要区别是什么。比如内存或性能影响
  • WPF 中是否存在“画笔始终为静态”和“模板始终为动态”等规则?

假设静态与动态之间的选择并不像看起来那么随意......但我看不到这种模式。

【问题讨论】:

  • 需要注意的是,Windows 8 应用程序开发人员没有 DyanmicResource 作为选项,只有 StaticResource。
  • @Jerry Nixon 感谢上帝,我已经记不清有多少次因为我使用的是 DynamicResource 而不是 StaticResource 而无法工作,反之亦然。从程序员的角度来看,这是不必要的复杂性。类比是变量定义,我是否必须明确指定它是位于堆上还是栈上?如果我弄错了,它会引发灾难性的运行时错误?
  • 有关 StaticResource 和 DynamicResource 的更详尽说明,以及何时使用它们,请参阅msdn.microsoft.com/en-us/library/ms750613%28v=vs.100%29.aspx

标签: .net wpf xaml resources


【解决方案1】:

StaticResource 将在应用程序实际运行之前加载 XAML 期间解析并分配给属性。它只会被分配一次,对资源字典的任何更改都会被忽略。

DynamicResource 在加载期间将一个 Expression 对象分配给该属性,但直到运行时要求该 Expression 对象提供值时才真正查找资源。这会延迟查找资源,直到在运行时需要它。一个很好的例子是对稍后在 XAML 中定义的资源的前向引用。另一个例子是直到运行时才存在的资源。如果源资源字典发生变化,它将更新目标。

【讨论】:

  • 在我需要使用 DynamicResource 之前需要进行哪些更改?以模板为例:我定义了一次,但当然触发器和东西可以改变模板的内容,但模板仍然是一样的。 StaticResource 会在这里做吗?
  • 如果您附加到的资源在其使用点之前在 XAML 中定义并且在应用程序运行的生命周期内不会更改,请使用 StaticResource。在这种情况下,您可以使用 StaticResource 获得更好的性能。
  • 双向绑定是否适用于这两种情况,如果是的话,在这种情况下会有什么区别?
  • 最后一句真的很重要:It will update the target if the source resource dictionary is changed.
  • @IsakSavo 考虑一个带有颜色主题的 UI,使用动态资源,您可以将一个字典换成另一个字典,并且新字典中引用资源的任何内容都会自动更新。
【解决方案2】:

StaticResource 将在对象构造时解析。
每次控件需要资源时,都会评估和解析 DynamicResource。

【讨论】:

    【解决方案3】:

    我也对它们感到困惑。请参阅下面的示例:

    <Window x:Class="WpfApplicationWPF.CommandsWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="CommandsWindow" Height="300" Width="300">
    
        <StackPanel>
            <Button Name="ButtonNew" 
                    Click="ButtonNew_Click" 
                    Background="{DynamicResource PinkBrush}">NEW</Button>
            <Image Name="ImageNew" 
                   Source="pack://application:,,,/images/winter.jpg"></Image>
        </StackPanel>
    
    
        <Window.Background>
            <DynamicResource ResourceKey="PinkBrush"></DynamicResource>
        </Window.Background>
    
    </Window>
    

    这里我为按钮和窗口使用了动态资源,并没有在任何地方声明它。运行时,将检查层次结构的ResourceDictionary。由于我没有定义它,我猜会使用默认值。

    如果我将下面的代码添加到 Button 的单击事件中,由于它们使用 DynamicResource,因此背景将相应更新。

    private void ButtonNew_Click(object sender, RoutedEventArgs e)
    {
        this.Resources.Add(  "PinkBrush"
                             ,new SolidColorBrush(SystemColors.DesktopColor)
                           );
    }
    

    如果他们使用了 StaticResource:

    • 资源必须在 XAML 中声明
    • 在使用它们之前也是如此。

    希望我消除了一些困惑。

    【讨论】:

      【解决方案4】:

      主要区别是什么。比如内存或性能影响

      静态资源和动态资源的区别在于底层对象发生变化时。如果您在 Resources 集合中定义的 Brush 在代码中被访问并设置为不同的对象实例,则 Rectangle 将不会检测到此更改。

      静态资源通过引用元素检索一次并在资源的生命周期内使用。然而,DynamicResources 每次使用时都会检索。

      动态资源的缺点是它们往往会降低应用程序的性能。

      WPF 中是否有“画笔始终是静态的”和“模板始终是动态的”等规则?

      最好的做法是使用静态资源,除非有特定的原因,比如您想动态更改代码中的资源。您希望使用动态资源的另一个示例包括使用 SystemBrushes、SystenFonts 和系统参数时。

      【讨论】:

        【解决方案5】:

        发现所有答案都很有用,只是想再添加一个用例。

        在复合 WPF 方案中,您的用户控件可以通过将资源称为 DynamicResource 来使用在任何其他父窗口/控件(将承载此用户控件)中定义的资源。

        正如其他人所说,静态资源将在编译时查找。用户控件不能引用托管/父控件中定义的那些资源。不过,在这种情况下可以使用 DynamicResource。

        【讨论】:

        • "Staticresource 将在编译时查找。".我不这么认为。 “编译时间”意味着“在构建应用程序时”。见Static resource lookup behavior首次加载 xaml 时会查找静态资源。这发生在运行时。静态和动态之间的区别在于静态查找只发生一次(并且遵循更简单的查找规则)。考虑“静态资源查找可以扩展到主题或系统资源””.
        • 啊,我在考虑页面如何使用您的控件,而不是您的控件可以在其资源字典中做什么。我明白你的意思 - “资源字典中的静态资源引用必须引用在资源引用之前已经在词法上定义的资源。” - 我认为这需要在编译时解析时间。
        【解决方案6】:

        动态资源的重要好处

        如果应用程序启动时间过长,则必须使用动态资源, 因为静态资源总是在创建窗口或应用程序时加载,而动态资源 首次使用时加载。

        但是,除非您的资源非常庞大且 复杂。

        【讨论】:

        • 对于 DynamicResources,是只创建一次性能问题(第一次使用)还是每次使用元素时都会出现?
        • 在这种情况下,大多数使用的字段必须是静态资源,自定义使用的字段可以是动态的,即主窗口资源是静态的,对话窗口资源可以是动态的
        • 在某些情况下,您不能通过在加载第二页的 XAML 之前编写添加到资源字典的代码来解决此限制吗?
        【解决方案7】:
        1. StaticResource 使用 first 值。 DynamicResource 使用 last 值。
        2. DynamicResource 可用于嵌套样式,StaticResource 不能。

        假设你有这个嵌套的 Style 字典。 LightGreen 位于根级别,而 Pink 嵌套在 Grid 中。

        <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
            <Style TargetType="{x:Type Grid}">
                <Style.Resources>
                    <Style TargetType="{x:Type Button}" x:Key="ConflictButton">
                        <Setter Property="Background" Value="Pink"/>
                    </Style>
                </Style.Resources>
            </Style>
            <Style TargetType="{x:Type Button}" x:Key="ConflictButton">
                <Setter Property="Background" Value="LightGreen"/>
            </Style>
        </ResourceDictionary>
        

        在视图中:

        <Window x:Class="WpfStyleDemo.ConflictingStyleWindow"
                xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                Title="ConflictingStyleWindow" Height="100" Width="100">
            <Window.Resources>
                <ResourceDictionary>
                    <ResourceDictionary.MergedDictionaries>
                        <ResourceDictionary Source="Styles/ConflictingStyle.xaml" />
                    </ResourceDictionary.MergedDictionaries>
                </ResourceDictionary>
            </Window.Resources>
            <Grid>
                <Button Style="{DynamicResource ConflictButton}" Content="Test"/>
            </Grid>
        </Window>
        

        StaticResource 会将按钮呈现为 LightGreen,这是它在样式中找到的第一个值。 DynamicResource 将在呈现网格时将 LightGreen 按钮覆盖为粉红色。

        静态资源

        动态资源

        请记住,VS Designer 将 DynamicResource 视为 StaticResource。它将获得第一个值。在这种情况下,VS Designer 会将按钮呈现为 LightGreen,尽管它实际上最终呈现为 Pink。

        当根级样式(LightGreen)被移除时,StaticResource 会抛出错误。

        【讨论】:

        • 仍然对如何在资源字典中首先找到 LightGreen 感到困惑,因为首先声明了 Pink(如上一个)。我猜当xaml 寻找它首先匹配“非嵌套”的样式时。不过,简短的解释会有所帮助。
        【解决方案8】:

        只有当属性被设置在从依赖对象或可冻结的对象上时,才能使用动态资源,因为静态资源可以在任何地方使用。 您可以使用静态资源抽象出整个控件。

        在以下情况下使用静态资源:

        1. 不需要在运行时更改反应资源时。
        2. 如果您需要大量资源的良好性能。
        3. 在同一字典中引用资源时。

        动态资源:

        1. 属性或样式设置器主题的值直到运行时才知道
          • 这包括系统、应用程序、基于主题的设置
          • 这也包括前向引用。
        2. 在加载页面、窗口、用户控件时引用可能无法加载的大型资源。
        3. 在自定义控件中引用主题样式。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-09-04
          • 1970-01-01
          • 2011-01-25
          • 2011-05-18
          • 2010-10-11
          • 2011-03-08
          相关资源
          最近更新 更多