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

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

或者作为一个动态资源

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

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

主要的区别是什么?比如对内存和性能的影响 WPF中是否存在“笔刷总是静态的”和“模板总是动态的”之类的规则?

我认为静态和动态之间的选择并不像看起来那么随意……但我看不出规律。


当前回答

我也对他们感到困惑。请看下面的例子:

<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。因为我没有定义它,所以我猜将使用默认值。

如果我添加下面的代码来click event of Button,因为他们使用的是DynamicResource,所以后台会相应更新。

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

如果他们使用了StaticResource:

资源必须在XAML中声明 这也是“before”他们被使用。

希望我澄清了你们的疑惑。

其他回答

我也对他们感到困惑。请看下面的例子:

<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。因为我没有定义它,所以我猜将使用默认值。

如果我添加下面的代码来click event of Button,因为他们使用的是DynamicResource,所以后台会相应更新。

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

如果他们使用了StaticResource:

资源必须在XAML中声明 这也是“before”他们被使用。

希望我澄清了你们的疑惑。

StaticResource将在对象构造时被解析。 DynamicResource将在每次控件需要该资源时被计算和解析。

StaticResource使用第一个值。DynamicResource使用last值。 DynamicResource可以用于嵌套样式,StaticResource不能。

假设您有这个嵌套样式字典。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按钮为粉红色,因为它呈现网格。

StaticResource

DynamicResource

请记住VS Designer将DynamicResource视为StaticResource。它会得到第一个值。在这种情况下,VS Designer将按钮渲染为浅绿色,尽管它实际上最终是粉红色。

当删除根级样式(LightGreen)时,StaticResource将抛出一个错误。

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

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

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

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

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