ChatGPT解决这个技术问题 Extra ChatGPT

WPF中的StaticResource和DynamicResource有什么区别?

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

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

或作为 DynamicResource

<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

M
Matt

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

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


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

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

<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 中声明

这也是“在”他们被使用之前。

希望我消除了一些困惑。


A
Afshin

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


J
Jeson Martajaya

StaticResource 使用第一个值。 DynamicResource 使用最后一个值。 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 按钮覆盖为粉红色。

https://i.stack.imgur.com/dYc0V.png

https://i.stack.imgur.com/MLGoJ.png

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

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


仍然混淆如何在资源字典中首先找到 LightGreen,因为首先声明了 Pink(如上面的另一个)。我猜当xaml 寻找它首先匹配“非嵌套”的样式时。不过,简短的解释会有所帮助。
C
CharithJ

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

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

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

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

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

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


M
Manish Basantani

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

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

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


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

动态资源的重要好处

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

但是,除非您的资源非常庞大和复杂,否则您不会看到任何好处。


对于 DynamicResources,它是只创建一次性能问题(第一次使用)还是每次使用元素时?
在这种情况下,大多数使用的字段必须是静态资源,自定义使用的字段可以是动态的,即主窗口资源是静态的,对话框窗口资源可以是动态的
在某些情况下,您不能通过在加载第二页的 XAML 之前编写添加到资源字典的代码来解决此限制吗?
W
Wolfgang

动态资源只能在设置的属性位于从依赖对象派生的对象上或可冻结的对象上使用,因为静态资源可以在任何地方使用。您可以使用静态资源抽象出整个控制。

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

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

动态资源:

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