原文:用实例讲DynamicResource与StaticResource的区别

之前我的博客文章"WPF中的资源(Resource)"中概略性地提到过DynamicResource与StaticResource的区别。其中有这么一句,确切地说是两句:静态资源在第一次编译后即确定其对象或值,之后不能对其进行修改。动态资源则是在运行时决定,当运行过程中真正需要时,才到资源目标中查找其值。

下面用例子更详细地说明DynamicResource与StaticResource的区别。

先看看这段XAML代码:
// LinearGradientBrush.xaml
<Window x:Class="BrawDraw.Com.LinearGradientBrush.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="LinearGradientBrush" Height="300" Width="300">
    <Canvas Background="{DynamicResource innerLgbResource}">
        <Canvas.Resources>
                <LinearGradientBrush StartPoint="0,0" EndPoint="0,1" x:Key="innerLgbResource">
                    <GradientStop Color="Yellow" Offset="0.0" />
                    <GradientStop Color="Orange" Offset="0.5" />
                    <GradientStop Color="Red" Offset="1" />
                </LinearGradientBrush>
        </Canvas.Resources>
    </Canvas>
</Window>
注意:innerLgbResource是基于Yellow, Orange, Red三种颜色的渐变。

相应的cs文件:
// LinearGradientBrush.xaml.cs
using System;
using System.Windows;

namespace BrawDraw.Com.LinearGradientBrush
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
        }
    }
}
运行的效果:

图1

注意XAML代码中的这句:<Canvas Background="{DynamicResource innerLgbResource}">,Canvas的背景使用了动态资源。
如果你将它改为<Canvas Background="{StaticResource innerLgbResource}">,将会收到错误提示:“StaticResource reference 'innerLgbResource' was not found.”
出现此问题的原因是:StaticResource 查询行为不支持向前引用,即不能引用在引用点之后才定义的资源
DynamicResource可以向前引用,即DynamicResource运行时才查找并加载所定义的资源。

接下来我们来“变变花样”。
先在App.xaml中加入应用程序级资源:
<Application x:Class="BrawDraw.Com.LinearGradientBrush.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="LinearGradientBrush.xaml">
    <Application.Resources>
        <LinearGradientBrush StartPoint="0,0" EndPoint="0,1" x:Key="appLgbResource">
            <GradientStop Color="Beige" Offset="0.0" />
            <GradientStop Color="Red" Offset="0.3" />
            <GradientStop Color="Yellow" Offset="0.5" />
            <GradientStop Color="Green" Offset="0.75" />
            <GradientStop Color="Orange" Offset="1" />
        </LinearGradientBrush>
        <Style TargetType="Canvas">
            <Setter Property="Background" Value="{StaticResource appLgbResource}">
            </Setter>
        </Style>
    </Application.Resources>
</Application>
注意<Application.Resources>...</Application.Resources>之间的部分。这里使用了从Beige, Red, Yellow, Green到Orange五种颜色的渐变。同时,将Canvas的背景属性使用Style/Setter的方式设置为这五种给定的渐变色。由于此五种颜色是一次性设置,之后不再改变,所以使用了StaticResource。

[讨论]
可以使用DynamicResource吗?
比如:<Setter Property="Background" Value="{DynamicResource appLgbResource}">
答案是:可以!

然后将LinearGradientBrush.xaml中<Canvas Background="{DynamicResource innerLgbResource}">这句改成:
<Canvas Background="{StaticResource appLgbResource}">,运行结果:

图2

接着试验:
(1)将<Canvas Background="{StaticResource appLgbResource}">改成:<Canvas Background="{DynamicResource appLgbResource}">试试,效果与图2一样!
(2)将<Canvas Background="{...}">中Background属性去掉,改成:<Canvas>,运行效果也与图2一致。
(3)如果改成:<Canvas Background="{DynamicResource innerLgbResource}">时,则显示图1所示基于基于Yellow, Orange, Red三种颜色的渐变效果。
(4)你甚至可以这样:
App.xml中使用<Setter Property="Background" Value="{DynamicResource appLgbResource}">,而在LinearGradientBrush.xaml中使用<Canvas Background="{StaticResource appLgbResource}">(运行效果如图2)。

探讨:
1、当引用资源时,选择StaticResource还是DynamicResource的考虑因素:
(1)在哪里创建资源?(资源的范围或层级
a. 资源是在一个Page/Canvas/Window中?
b. 在应用程序范围中?
c. 在松散的Xaml中?
d. 在某个特定的Object(比如某个特定的Button)中?
物件级:此时,资源只能套用在这个Object物件,或套用至该物件的子物件。
文件级:如果将资源定义在Window或Page层级的XAML档中,那么可以套用到这个文件中的所有物件。
应用程序级:如果我们将资源定义在App.xaml 中,那么,就可以将资源套用到应用程序内的任何地方。
字典级:当我们把资源封装成一个资源字典, 定义到一个ResourceDictionary的XAML文件时,就可以在另一个应用程序中重复使用。

(2) 应用程序的功能:是否在运行时改变资源?
如果需要改变,则使用DynamicResource。
(3) 每个资源引用类型不同的寻找行为。(需要支持向前引用吗?)

StaticResources的适用场合:
(1)在资源第一次引用之后无需再修改资源的值。
(2)资源引用不会基于运行时的行为进行重新计算,比如在重新加载Page/Window的时候。
(3)当需要设置的属性不是DependencyObject或Freezable类型的时候,用StaticResource。
(4)当需要将资源编译到dll中,并打包为程序的一部份,或者希望在各应用程序之间共享时,也使用StaticResource。
(5)当需要为一个自定义控件创建一个Theme,并Theme中使用资源,就需要使用StaticResource。因为StaticResource的资源查找行为时可预测的,并且本身包含在Theme中。而对于DynamicResource,即使资源是定义在Theme中,也只能等到运行时确定,导致一些可能意料不到的情况发生。
(6)当需要使用资源设置大量的依赖属性(Dependency Property)的时候。
由于依赖属性具有属性系统提供的值缓存机制,所以,如果能在程序装载时设置依赖属性的值,这样,依赖属性就不需要检查自己的值并返回最后的有效值了。
 
Dynamic Resource一般使用在如下场合:
(1)资源的值依赖一些条件,而该条件直到运行时才能确定。
包括系统资源,或是用户可设置的资源。比如:可以创建引用系统属性诸如SystemColors,SystemFonts来设置值,而这些属性是动态的,它们的值又来自于运行环境和操作系统。
(2)为自定义控件引用或创建Theme Style。
(3)希望在程序运行期间调整资源字典的内容时。
(4)希望资源可以向前引用时(如上面在Canvas中引用innerLgbResource一样)
(5)资源文件很大,希望在运行时才加载。
(6)要创建的Style的值可能来自于其它值,而这些值又依赖于Theme或用户的设置。
(7)当引用资源的元素的父元素有可能在运行期改变,这个时候也需要使用动态资源。因为父元素的改变将导致资源查询的范围。
Dynamic resource的限制条件:属性必须是依赖属性,或是Freezable的。

资源的查询方式
Static Resource的查询
(1)查找使用该资源的元素的Resource字典;
(2)顺着逻辑树向上查找父元素的资源字典,直到根节点;
(3)查找Application资源;
(4)不支持向前引用,即:不能引用在引用点之后才定义的资源。

Dynamic Resource的查询
(1)查找使用该资源的元素的Resource字典;
如果元素定义了一个Style 属性,将查找Style中的资源字典;如果元素定义了一个Template属性,将查找FrameworkTemplate中的资源字典。
(2)顺逻辑树向上查找父元素的资源字典,直到根节点;
(3)查找Application资源;
(4)查找当前激活状态下的Theme资源字典;
(5)查找系统资源。

用实例讲DynamicResource与StaticResource的区别的更多相关文章

  1. [WPF系列]-DynamicResource与StaticResource的区别

    探讨: 1.当引用资源时,选择StaticResource还是DynamicResource的考虑因素: (1)在哪里创建资源?(资源的范围或层级) a. 资源是在一个Page/Canvas/Wind ...

  2. WPF中的资源简介、DynamicResource与StaticResource的区别

    原文:WPF中的资源简介.DynamicResource与StaticResource的区别 什么叫WPF的资源(Resource)?资源是保存在可执行文件中的一种不可执行数据.在WPF的资源中,几乎 ...

  3. DynamicResource与StaticResource的区别

    原文:DynamicResource与StaticResource的区别 2008-06-20 12:16:12 静态资源在第一次编译后即确定其对象或值,之后不能对其进行修改.动态资源则是在运行时决定 ...

  4. WPF中的资源简介、DynamicResource与StaticResource的区别(转)

    什么叫WPF的资源(Resource)?资源是保存在可执行文件中的一种不可执行数据.在WPF的资源中,几乎可以包含图像.字符串等所有的任意CLR对象,只要对象有一个默认的构造函数和独立的属性. 也就是 ...

  5. iOS 成员变量,实例变量,属性变量的区别,联系

    在ios第一版中: 我们为输出口同时声明了属性和底层实例变量,那时,属性是oc语言的一个新的机制,并且要求你必须声明与之对应的实例变量,例如: 注意:(这个是以前的用法) @interface MyV ...

  6. 32位汇编第一讲x86和8086的区别,以及OllyDbg调试器的使用

    32位汇编第一讲x86和8086的区别,以及OllyDbg调试器的使用 一丶32位(x86也称为80386)与8086(16位)汇编的区别 1.寄存器的改变 AX 变为 EAX  可以这样想,16位通 ...

  7. Thread.currentThread().getName() ,对象实例.getName() 和 this.getName()区别

    原文链接:http://www.cnblogs.com/signheart/p/922dcf75dd5fe6b418d4475af89c4664.html 使用Thread.currentThread ...

  8. Oracle实例名,服务名等概念区别与联系

    数据库名.实例名.数据库域名.全局数据库名.服务名 , 这是几个令很多初学者容易混淆的概念.相信很多初学者都与我一样被标题上这些个概念搞得一头雾水.我们现在就来把它们弄个明白. 一.数据库名 什么是数 ...

  9. 实例-PHP_SELF、 SCRIPT_NAME、 REQUEST_URI区别-获取前台公用文-dirname-PHP的"魔术常量"-str_replace

    Part1:实例 $_SERVER[PHP_SELF], $_SERVER[SCRIPT_NAME], $_SERVER['REQUEST_URI'] 在用法上是非常相似的,他们返回的都是与当前正在使 ...

随机推荐

  1. struts2注入类

    struts2是能够注入一个对象的,那么一定须要继承ModelDriven的泛型接口. package com.test.action; import com.opensymphony.xwork2. ...

  2. ios开发网络学习十二:NSURLSession实现文件上传

    #import "ViewController.h" // ----WebKitFormBoundaryvMI3CAV0sGUtL8tr #define Kboundary @&q ...

  3. 用IBM WebSphere DataStage进行数据整合: 第 1 部分 分类: H2_ORACLE 2013-08-23 11:20 688人阅读 评论(0) 收藏

    转自:http://www.ibm.com/developerworks/cn/data/library/techarticles/dm-0602zhoudp/ 引言 传统的数据整合方式需要大量的手工 ...

  4. AOP概述:

    AOP可以在不修改源代码的情况下,对程序进行增强. AOP面向切面进行编程,Spring将AOP引入到框架中,但是也需要遵守AOP联盟的规范. 通过预编译的方式和运行期动态代理实现程序功能的同意维护的 ...

  5. crx

    https://www.crx4chrome.com/down/770/crx/ Downloading crx file for Linkclump The Linkclump crx file y ...

  6. Android 升级到android studio 2.2项目死活run不起来

    背景:升级到Android studio 2.2项目死活运行不起来 现象如下: run with --stacktrace --debug等等抛出的bug简直无法忍视 解决办法:把compileSdk ...

  7. [CSS] Build Responsive CSS Layouts with Tachyons

    Building responsive css layouts is critical in any modern website. Tachyons makes this easy by desig ...

  8. oracle改动登录认证方式

    通过配置sqlnet.ora文件.我们能够改动oracle登录认证方式. SQLNET.AUTHENTICATION_SERVICES=(NTS);基于操作系统的认证 SQLNET.AUTHENTIC ...

  9. form的get与post方式的区别(转)

    form元素的method属性用来指定发送form的http方法 使用get时,form数据集被附加到form元素的action属性所指定的URL后面,仅仅是拼接一个URL,然后直接向服务区请求数据, ...

  10. 【t071】最长路

    Time Limit: 1 second Memory Limit: 128 MB [问题描述] 设G为有n个顶点的有向无环图,G中各顶点的编号为1到n.设w[i,j]为边的长度.请计算图G中从1到n ...