转自:http://www.fx114.net/qa-261-90254.aspx

我们应该都知道,XAML是一种声明式语言,XAML的标签声明的就是对象。一个XAML标签会对应着一个对象,这个对象一般会是一个控件类的实例。在.Net平台上,所有类都是引用类型,我们是通过引用来访问对象实例。当一个对象实例不再被任何引用者引用时,它将自动被GC回收。

在WPF开发过程中,后台代码经常会操作前台XAML声明的控件对象实例,这就涉及到如何查找这些控件对象的引用。

有两种方式可以查找前台控件对象的引用,以下分别介绍:

方式1:利用引用者的层级关系来查找控件对象引用

window x:Class="WpfApplication1.Window1"
                         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
                         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                         xmlns:local="clr-namespace:WpfApplication1"
                        Title="WindowServer" Height="300" Width="300" MaxWidth="500" MaxHeight="600" MinHeight="200" MinWidth="200">
                          <StackPanel >

<Button Content="OK" Margin="5" Click="Button_Click"/>
                                        <TextBox  Margin="5,0" Height="100" >
                           </StackPanel>
                </Window>
       以上是用XAML申明了两个控件对象实例,下面后台代码Button控件点击事件器,需要完成对TextBox的内容填字一段字符串。

private void Button_Click(object sender, RoutedEventArgs e)
         {
             StackPanel stackPanel = this.Content as StackPanel;  //this.Content属性引用着StackPanel的实例
             TextBox textBox = stackPanel.Children[1] as TextBox;   //StackPanel实例的Children[1]引用着TextBox实例
             textBox.Text = "Hello,World!";
         }

通过这个关系就可以一路查找下来,同时进行类型的转换。看懂以上关系,那么就很容易知道stackPanel.Childere[0]引用的对象是什么了。

方式2:利用XAML申明的控件引用变量名引用控件对象实例

window x:Class="WpfApplication1.Window1"
                         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
                         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                         xmlns:local="clr-namespace:WpfApplication1"
                        Title="WindowServer" Height="300" Width="300" MaxWidth="500" MaxHeight="600" MinHeight="200" MinWidth="200">
                          <StackPanel >

<Button x:Name="button" Content="OK" Margin="5" Click="Button_Click"/>
                                        <TextBox x:Name="textBox"  Margin="5,0" Height="100" >
                           </StackPanel>
                </Window>
       我们从方式1很容易发现,使用这种方法访问UI上的所有控件对象实例太繁琐了。XAML通过为对象声明引用变量,后台代码通过引用变量就可以直接获取到该对象引用。

而XAML申明对象的引用变量是使用x:Name来做到的。原则上,所有UI控件都存在该属性。

查看以上XAML申明,发现它和方式1唯一的区别是控件了x:Name的引用变量声明。这时,我们的后台代码获取控件对象实例方法如下:

private void Button_Click(object sender, RoutedEventArgs e)
         {
            // StackPanel stackPanel = this.Content as StackPanel;  //this.Content属性引用着StackPanel的实例
             //TextBox textBox = stackPanel.Children[1] as TextBox;   //StackPanel实例的Children[1]引用着TextBox实例
             textBox.Text = "Hello,World!";
         }

这段代码通过XAML申明的对象引用变量直接访问对象,相对方式1确实简洁多了,呵呵。那么如何我们需要访问Button对象呢,当然直接使用button就OK了。

这里需要提一点,x:Name申明对象引用变量的同时,如果控件存在Name属性,那么采用x:Name将一举两得,可自动对Name属性赋值,赋值的名称当然与引用变量名称相同。所以,建议使用x:Name,因为它的功能已涵盖了控件的Name属性功能,可以增强代码的统一性和可读性。

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

后台代码除了经常访问前台XAML声明的控件对象实例,还会经常访问前台声明的控件资源。

看一下以下这段XAML申明:

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication1"
    xmlns:sys="clr-namespace:System;assembly=mscorlib"
    Title="WindowServer" Height="300" Width="300" MaxWidth="500" MaxHeight="600" MinHeight="200" MinWidth="200">
    <Window.Resources>
        <sys:String x:Key="myString">Hello,World!</sys:String>
    </Window.Resources>
    <StackPanel>

<Button x:Name="button1" Content="Send Command" Margin="5" Click="Button_Click" >
        <TextBox x:Name="textBoxA" Margin="5,0" Height="100" >
    </StackPanel>
 </Window>

这段XAML声明和之前的没什么区别,除了黑体字部分。这段申明是向Window.Resources资源字典添加一个条目,条目的内容是一段字符串。

再仔细观察,你会发现除了字符串,还有x:Key="myString"这一语句。它的作用是干嘛呢,很简单是建立资源字典的键值对,方便索引资源条目。如何使用过C++的STL,对Map应该就不陌生。这个x:Key就相当于Map的key。下面看一看,后台代码如何访问这段字符串。

private void Button_Click(object sender, RoutedEventArgs e)
         {
                string str = this.FindResource("myString") as string;  //调用一个拥有Resource属性对象的FindResource方法就可以从资源字典里检索资源

this.textBox.Text = str;

}

值得注意一下,检索资源返回的是Object对象,需要根据相应类型转换即可。

除了后台代码经常检索控件资源,前台控件也可能会访问该资源,引用的方法是使用StaticResource或DynamicResource.

下面的示例在page的根元素定义了一个SolidColorBrush画刷作为一个资源,并展示如何用它来设置Page中子元素的属性
<Page Name="root"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

<Page.Resources>
    <SolidColorBrush x:key=”MyBrush” Color=”Gold”/>
    <Style TargetType=”Border” x:Key=”PageBackground”>
       <Setter Property=”Background” Value=”Blue”/>
    </Style>
<Page.Resources>
    <SolidColorBrush x:Key="MyBrush" Color="Gold"/>
    <Style TargetType="Border" x:Key="PageBackground">
      <Setter Property="Background" Value="Blue"/>
    </Style>
   
</Page.Resources>
 <StackPanel>
    <DockPanel>
        <Button DockPanel.Dock="Top" HorizontalAlignment="Left" Height="30" Background="{StaticResource MyBrush}" Margin="40">Button</Button>
              </DockPanel>
 </StackPanel>
</Page>
 
每个框架级别的元素(FrameworkElement或FrameworkContentElement)都有一个Resources属性,我们可以在任何元素上定义资源,不过习惯上在根元素上定义,如上面 的XAML代码中<Page.Resources/>定义资源。
       通过属性x:Key给每个资源赋予一个唯一的关键字。这样我们就可以在XAML的其它地方通过Key值来操作对应的资源了。如下示例,使用资源给元素的属性赋值
<Button Background=”{StaticResource MyBrush}” />
 
StaticResource 和DynamicResource的区别:
 
资源可以被当作StaticResource和DynamicResource两种类型来引用。

当引用资源时,下面的考虑将影响你是选择StaticResource还是DynamicResource来它。
1〉 如何为应用程序创建资源(资源是在一个Page中,在APP范围还是在松散的Xaml中或仅仅在程序集中)
2〉 应用程序功能:是否在运行时改变资源
3〉 每个资源引用类型不同的寻找行为
StaticResources
StaticResources在如下情况下使用比较好
1〉 在资源第一次引用之后无需再修改资源的值
2〉 StaticResource引用不会基于运行时的行为进行重新计算。比如在重新加载Page的时候。
3〉 当需要设置的属性不是DependencyObject或Freezable类型的时候,需要用staticResource
4〉 当需要将资源编译到dll中,并打包为程序的一部份,或者希望在各应用程序之间共享
5〉 当需要为一个自定义控件创建一个theme,并theme中使用资源,就需要使用StaticResource。因为StaticResource的资源查找行为时可预测的,并且本身包含在theme中。而对于DynamicResource,即使资源是定义在theme中,也只能等到运行时确定,导致一些可能意料不到的情况发生。
6〉 当需要使用资源设置大量的依赖属性的时候(dependency property),依赖属性具有属性系统提供的值缓存机制,所以如果能在程序装载时设置依赖属性的值,依赖属性就不需要检查自己的值并返回最后的有效值了。可以获得显示时的好处。
Static resource 查询行为
1〉 查找使用该资源的元素的resource字典
2〉 顺逻辑树向上查找父元素的资源字典,直到根节点
3〉 查找Application资源
4〉 不支持向前引用。即不能引用在引用点之后才定义的资源
 
Dynamic Resource
Dynamic resources一般使用在如下场合
1〉 资源的值依赖一些条件,而该条件直到运行时才能确定。这包括系统资源,或是用户可设置的资源。例如,可以创建引用系统属性诸如SystemColors,SystemFonts来设置值,这些属性是动态的,他们的值来自于运行环境和操作系统
2〉 为自定义控件引用或创建theme style
3〉 希望在程序运行期间调整资源字典的内容
4〉 希望资源可以向前引用
5〉 资源文件很大,希望在运行时加载
6〉 要创建的style的值可能来自于其它值,而这些值又依赖于themes或用户设置
7〉 当引用资源的元素的父元素有可能在运行期改变,这个时候也需要使用动态资源。因为父元素的改变将导致资源查询的范围。
Dynamic resource 查询行为
1〉 查找使用该资源的元素的resource字典
如果元素定义了一个Style 属性,将查找Style中的资源字典
如果元素定义了一个Template属性,将查找FrameworkTemplate中的资源字典
2〉 顺逻辑树向上查找父元素的资源字典,直到根节点
3〉 查找Application资源
4〉 查找当前激活状态下的theme资源字典。
5〉 查找系统资源
Dynamic resource的限制条件
1〉 属性必须是依赖属性,或是Freezable的

笔记04 WPF对象引用的更多相关文章

  1. 笔记04 WPF的Binding

    oneWay:使用 OneWay 绑定时,每当源发生变化,数据就会从源流向目标. OneTime: 绑定也会将数据从源发送到目标:但是,仅当启动了应用程序或 DataContext 发生更改时才会如此 ...

  2. JS自学笔记04

    JS自学笔记04 arguments[索引] 实参的值 1.对象 1)创建对象 ①调用系统的构造函数创建对象 var obj=new Object(); //添加属性.对象.名字=值; obj.nam ...

  3. JAVA自学笔记04

    JAVA自学笔记04 1.switch语句 1)格式:switch(表达式){ case 值1: 语句体1; break; case 值2: 语句体2; break; - default: 语句体n+ ...

  4. 机器学习实战(Machine Learning in Action)学习笔记————04.朴素贝叶斯分类(bayes)

    机器学习实战(Machine Learning in Action)学习笔记————04.朴素贝叶斯分类(bayes) 关键字:朴素贝叶斯.python.源码解析作者:米仓山下时间:2018-10-2 ...

  5. CS229 笔记04

    CS229 笔记04 Logistic Regression Newton's Method 根据之前的讨论,在Logistic Regression中的一些符号有: \[ \begin{eqnarr ...

  6. 【HLSL学习笔记】WPF Shader Effect Library算法解读之[DirectionalBlur]

    原文:[HLSL学习笔记]WPF Shader Effect Library算法解读之[DirectionalBlur] 方位模糊是一个按照指定角度循环位移并叠加纹理,最后平均颜色值并输出的一种特效. ...

  7. 【HLSL学习笔记】WPF Shader Effect Library算法解读之[Embossed]

    原文:[HLSL学习笔记]WPF Shader Effect Library算法解读之[Embossed] Embossed(浮雕效果)          浮雕效果主要有两个参数:Amount和Wid ...

  8. 【HLSL学习笔记】WPF Shader Effect Library算法解读之[BandedSwirl]

    原文:[HLSL学习笔记]WPF Shader Effect Library算法解读之[BandedSwirl] 因工作原因,需要在Silverlight中使用Pixel Shader技术,这对于我来 ...

  9. SaToken学习笔记-04

    SaToken学习笔记-04 如果有问题,请点击:传送门 角色认证 在sa-token中,角色和权限可以独立验证 // 当前账号是否含有指定角色标识, 返回true或false StpUtil.has ...

随机推荐

  1. 用JS去掉前后空格或中间空格大全

    1.  去掉字符串前后所有空格: -- js实现trim功能 //去除字符串前后所有空 function Trim(str) { return str.replace(/(^\s*)|(\s*$)/g ...

  2. 移动端可拖动导航菜单小demo

    <!DOCTYPE html> <html lang="en"> <head> <title>移动端滑动导航菜单</title ...

  3. hihoCoder #1161 八卦的小冰

    题目大意 考虑一个由 $n$ 个人构成的社交网络,其中任意两人都有一个用非负整数表示的亲密度. 初始时给出 $m$ 对人的亲密度,其余的亲密度为 $0$ . 定义此社交网络的「八卦度」为异性之间的亲密 ...

  4. NOJ——1649Find Sum(二分查找)

    [1649] Find Sum 时间限制: 1000 ms 内存限制: 65535 K 问题描述 This problem is really boring. You are given a numb ...

  5. [luoguP1640] [SCOI2010]连续攻击游戏(二分图最大匹配)

    传送门 我们将每一个属性和物品连边,然后枚举从小到大属性跑匈牙利,直到找不到连边 #include <cstdio> #include <cstring> #include & ...

  6. chromedriver对应的支持的Chrome版本(更新至Chrome64)

    很多网友在配置chromedriver的时候会遇到很多麻烦,在网上找了很多资料觉得这个表格不错,就给大家分享出来,希望对大家配置chrome的时候有帮助: chromedriver版本 支持的Chro ...

  7. 仔细瞄一下HashMap是怎么干活的

    以下分析基于jdk11.0.2 1. 创建HashMap时发生了什么? HashMap(),HashMap(int initialCapacity),HashMap(int initialCapaci ...

  8. Python ping 模块

    使用socket模块也可以获得域名对应的ip,参考:https://blog.csdn.net/c465869935/article/details/50850598 print socket.get ...

  9. Docker 使用指南—— 基本操作

    版权声明:本文由田飞雨原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/98来源:腾云阁 https://www.qcloud ...

  10. 卡牌游戏(bzoj 3191)

    Description   N个人坐成一圈玩游戏.一开始我们把所有玩家按顺时针从1到N编号.首先第一回合是玩家1作为庄家.每个回合庄家都会随机(即按相等的概率)从卡牌堆里选择一张卡片,假设卡片上的数字 ...