WPF入门教程系列十二——依赖属性(二)
二、 依赖属性的优先级
由于WPF 允许我们可以在多个地方设置依赖属性的值,所以我们就必须要用一个标准来保证值的优先级别。比如下面的例子中,我们在三个地方设置了按钮的背景颜色,那么哪一个设置才会是最终的结果呢?是Black、Red还是Azure呢?
<Window x:Class="WpfApp1.WindowDepend"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WindowDepend" Height="400" Width="400">
<Grid>
<Button x:Name="myButton" Background="Azure">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="Black"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
Click
</Button>
</Grid>
</Window>
通过前面的简单介绍,我们了解了简单的依赖属性,每次访问一个依赖属性,它内部会按照下面的顺序由高到底处理该值。详细见下图

由于这个流程图偏理想化,在实际的工作过程中我们会遇到各种各样的问题,我也不可能都碰到,也就无法彻底把这些问题说清楚,所以当我们遇到问题之后,再进行仔细分析,查找原因,不断总结、举一反三。
三、 依赖属性的继承
属性值继承是 Windows Presentation Foundation (WPF) 属性系统的一项功能。 属性值继承使元素树中的子元素可以从父元素那里获取特定属性的值,并继承该值,就好像它是在最近的父元素中的任意位置设置的一样。 父元素还可以通过属性值继承来获得其值,因此系统有可能一直递归到页面根元素。 属性值继承不是属性系统的默认行为;属性必须用特定的元数据设置来建立,以便使该属性能够对子元素启动属性值继承。
依赖属性继承的最初意愿是父元素的相关设置会自动传递给所有层次的子元素 ,即元素可以从其在树中的父级继承依赖项属性的值。这个我们在编程当中接触得比较多,如当我们修改窗体父容器控件的字体设置时,所有级别的子控件都将自动 使用该字体设置 (前提是该子控件未做自定义设置)。接下来,我们来做一个实际的例子。代码如下:
<Window x:Class="WpfApp1.WindowInherited"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WindowInherited" Height="400" Width="500" Loaded="Window_Loaded" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="101*"/>
<RowDefinition Height="80"/>
<RowDefinition Height="80"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" >
<Label Content="继承自Window的FontSize" />
<TextBlock Name="textBlockInherited" Text="重写了继承,没有继承Window的FontSize"
FontSize="36" TextWrapping="WrapWithOverflow"/>
<StatusBar>没有继承自Window的FontSize,Statusbar</StatusBar>
</StackPanel>
<WrapPanel Grid.Row="1">
<Label Content="窗体字体大小" />
<ComboBox Name="drpWinFontSize"></ComboBox>
<Button Name="btnFontSize" Click="btnFontSize_Click">改变window字体</Button>
</WrapPanel>
<WrapPanel Grid.Row="2">
<Label Content="文本字体大小" />
<ComboBox Name="drpTxtFontSize"></ComboBox>
<Button Name="btnTextBlock" Click="btnTextBlock_Click">改变TextBlock字体</Button>
</WrapPanel>
</Grid>
</Window>
代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace WpfApp1
{
/// <summary>
/// WindowInherited.xaml 的交互逻辑
/// </summary>
public partial class WindowInherited : Window
{
public WindowInherited()
{
InitializeComponent();
}
private void btnFontSize_Click(object sender, RoutedEventArgs e)
{
this.FontSize =Convert.ToInt32(drpWinFontSize.Text);
}
private void btnTextBlock_Click(object sender, RoutedEventArgs e)
{
this.textBlockInherited.FontSize = Convert.ToInt32(drpTxtFontSize.Text);
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
List<int> listFontSize = new List<int>();
for (int i = 0; i <= 60; i++)
{
listFontSize.Add(i + 4);
}
drpTxtFontSize.ItemsSource = listFontSize;
drpWinFontSize.ItemsSource = listFontSize;
}
}
}
效果图如下:

Window.FontSize 设置会影响所有的内部元素字体大小,这就是所谓的属性值继承,如上面代码中的第一个Label没有定义FontSize ,所以它继承了Window.FontSize的值。但一旦子元素提供了显式设置,这种继承就会被打断,如第二个TextBlock定义了自己的 FontSize,所以这个时候继承的值就不会再起作用了。
这个时候你会发现一个很奇怪的问题:虽然StatusBar没有重写FontSize,同时它也是Window的子元素,但是它的字体大小却没 有变化,保持了系统默认值。那这是什么原因呢?作为初学者可能都很纳闷,官方不是说了原则是这样的,为什么会出现表里不一的情况呢?其实仔细研究才发现并 不是所有的元素都支持属性值继承。还会存在一些意外的情况,那么总的来说是由于以下两个方面:
1、有些Dependency属性在用注册的时候时指定Inherits为不可继承,这样继承就会失效了。
2、有其他更优先级的设置设置了该值,在前面讲的的“依赖属性的优先级”你可以看到具体的优先级别。
属性值继承通过混合树操作。持有原始值的父对象和继承该值的子对象都必须是 FrameworkElement 或 FrameworkContentElement,且都必须属于某个逻辑树。 但是,对于支持属性继承的现有 WPF 属性,属性值的继承能够通过逻辑树中没有的中介对象永久存在。 这主要适用于以下情况:让模板元素使用在应用了模板的实例上设置的所有继承属性值,或者使用在更高级别的页级成分(因此在逻辑树中也位于更高位置)中设置的所有继承属性值。 为了使属性值的继承在这两种情况下保持一致,继承属性必须注册为附加属性。
这里的原因是部分控件如StatusBar、Tooptip和Menu等内部设置它们的字体属性值以匹配当前系统。这样用户通过操作系统的控制 面板来修改它们的外观。这种方法存在一个问题:StatusBar等截获了从父元素继承来的属性,并且不影响其子元素。比如,如果我们在 StatusBar中添加了一个Button。那么这个Button的字体属性会因为StatusBar的截断而没有任何改变,将保留其默认值。所以大家 在使用的时候要特别注意这些问题。
WPF入门教程系列十二——依赖属性(二)的更多相关文章
- WPF入门教程系列十四——依赖属性(四)
六.依赖属性回调.验证及强制值 我们通过下面的这幅图,简单介绍一下WPF属性系统对依赖属性操作的基本步骤: 借用一个常见的图例,介绍一下WPF属性系统对依赖属性操作的基本步骤: 第一步,确定Base ...
- WPF入门教程系列十八——WPF中的数据绑定(四)
六.排序 如果想以特定的方式对数据进行排序,可以绑定到 CollectionViewSource,而不是直接绑定到 ObjectDataProvider.CollectionViewSource 则会 ...
- WPF入门教程系列十六——WPF中的数据绑定(二)
三.绑定模式 通过上一文章中的示例,学习了简单的绑定方式.在这里的示例,要学习一下绑定的模式,和模式的使用效果. 首先,我们来做一个简单示例,这个示例是根据ListBox中的选中项,去改变TextBl ...
- WPF入门教程系列十五——WPF中的数据绑定(一)
使用Windows Presentation Foundation (WPF) 可以很方便的设计出强大的用户界面,同时 WPF提供了数据绑定功能.WPF的数据绑定跟Winform与ASP.NET中的数 ...
- WPF入门教程系列十九——ListView示例(一)
经过前面的学习,今天我做一个比较综合的WPF程序示例,主要包括以下功能: 1) 查询功能.从数据库(本地数据库(local)/Test中的S_City表中读取城市信息数据,然后展示到WPF的Windo ...
- WPF入门教程系列十——布局之Border与ViewBox(五)
九. Border Border 是一个装饰的控件,此控件绘制边框及背景,在 Border 中只能有一个子控件,若要显示多个子控件,需要将一个附加的 Panel 控件放置在父 Border 中.然后可 ...
- WPF入门教程系列二十三——DataGrid示例(三)
DataGrid的选择模式 默认情况下,DataGrid 的选择模式为“全行选择”,并且可以同时选择多行(如下图所示),我们可以通过SelectionMode 和SelectionUnit 属性来修改 ...
- WPF入门教程系列二——Application介绍
一.Application介绍 WPF和WinForm 很相似, WPF与WinForm一样有一个 Application对象来进行一些全局的行为和操作,并且每个 Domain (应用程序域)中仅且只 ...
- WPF入门教程系列(二) 深入剖析WPF Binding的使用方法
WPF入门教程系列(二) 深入剖析WPF Binding的使用方法 同一个对象(特指System.Windows.DependencyObject的子类)的同一种属性(特指DependencyProp ...
随机推荐
- .Net Webconfig连接字符串中数据库实例名带'\'的问题
获取前: 获取后: 导致sa登录失败的问题 string strCon = "workstation id=localhost;packet size=4096;user id=" ...
- python+selenium+Robot
准备工作: 1.下载python2.7 http://python.org/getit/ 2.下载下载setuptools [python 的基础包工具] 可以帮助我们轻松的下载,构建,安装,升级,卸 ...
- 关于netty
现在我们一般使用应用程序或者链接库相互进行通信.例如,我们经常通过一个使用http协议的客户端链接库,从网站服务器中获得信息,并且通过网站服务,调用一些远程程序. 然而,一些通用协议或者它们的实现方式 ...
- 开发框架Data Abstract和Hydra发布版本Winter 2013
Data Abstract Winter 2013即Data Abstract Version 7.0.73 (Build .1111),Winter 2013版对Data Abstract继续做了以 ...
- 使用小技巧,让你高效使用Eclipse
1.自动完成--Eclipse有一个自动完成代码功能,快捷键是ctrl + space.当点击时就会弹出一个对话框,上面有与前后文相关的一些建议.只要有一个可能性,Eclipse就会替你完成. 2.快 ...
- ArcGIS百米网格自动生成
最近需要用百米网格进行空间叠加分析,首先得自动生成百米网格数据.经过查找,发现ARCgis可以自动生成网格.方法如下 2.创建格网(Creat Fishnet).需要用到ArcGIS的ArcToolb ...
- input文本框去除单击时的边框的方法
前端开发写的input文本框标签后单击时可以看到有边框,去除边框的方法: input{ outline:medium; }
- springMVC中一个controller多个方法
web.xml文件: <?xml version="1.0" encoding="UTF-8"?><web-app version=" ...
- rhel 5.8下静默安装oracle11gr2
1.图形界面下录制脚本如下: #-------------------------------------------------------------------------------# Do ...
- 《与mysql零距离接触》视屏学习笔记
1.数据表的增删改查操作(crud): 对于表: 增:create table XXXX 删:drop table XXXX 改:alter table XXXX rename to XXXX 查 ...