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>

代码


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

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的截断而没有任何改变,将保留其默认值。所以大家 在使用的时候要特别注意这些问题。

时间: 2024-10-12 11:38:11

WPF入门教程系列十二——依赖属性(二)的相关文章

WPF入门教程系列十四——依赖属性(四)

六.依赖属性回调.验证及强制值 我们通过下面的这幅图,简单介绍一下WPF属性系统对依赖属性操作的基本步骤: 借用一个常见的图例,介绍一下WPF属性系统对依赖属性操作的基本步骤: 第一步,确定Base Value,对同一个属性的赋值可能发生在很多地方.比如控件的背景(Background),可能在Style或者控件的构造函数中都对它进行了赋值,这个Base Value就要确定这些值中优先级最高的值,把它作为Base Value. 第二步,估值.如果依赖属性值是计算表达式(Expression),比

WPF入门教程系列十八——WPF中的数据绑定(四)

六.排序 如果想以特定的方式对数据进行排序,可以绑定到 CollectionViewSource,而不是直接绑定到 ObjectDataProvider.CollectionViewSource 则会成为数据源,并充当截取 ObjectDataProvider 中的数据的媒介,并提供排序.分组和筛选功能,然后将它传送到目标. 这个显示是使用 CollectionViewSource做为排序的数据源,首先将CollectionViewSource的Source 属性设置为 ObjectDataPr

WPF入门教程系列十五——WPF中的数据绑定(一)

使用Windows Presentation Foundation (WPF) 可以很方便的设计出强大的用户界面,同时 WPF提供了数据绑定功能.WPF的数据绑定跟Winform与ASP.NET中的数据绑定功能类似,但也有所不同,在 WPF中以通过后台代码绑定.前台XAML中进行绑定,或者两者组合的方式进行数据绑定.您可以绑定控件.公共属性.XML 或对象,WPF中的数据绑定跟WinForm与ASP.NET相比,更加快捷.灵活和简单. 一.什么是数据绑定 WPF 中的数据绑定,必须要有绑定目标和

WPF入门教程系列十——布局之Border与ViewBox(五)

九. Border Border 是一个装饰的控件,此控件绘制边框及背景,在 Border 中只能有一个子控件,若要显示多个子控件,需要将一个附加的 Panel 控件放置在父 Border 中.然后可以将子控件放置在该 Panel控件中. Border 的几个重要属性: Background:用用一个 Brush 对象来绘制背景 : BorderBrush:用一个Brush 对象来绘制边框 : BorderThickness:此属性设置 Border 边框的大小: CornerRadius:此属

WPF入门教程系列十九——ListView示例(一)

经过前面的学习,今天我做一个比较综合的WPF程序示例,主要包括以下功能: 1) 查询功能.从数据库(本地数据库(local)/Test中的S_City表中读取城市信息数据,然后展示到WPF的Window上的一个ListView上. 2) 数据联动功能.当鼠标左键选中ListView中的某一条记录时,在ListView框下面文本框中显示详细信息. 3) 修改功能.修改TextBox中的内容后,点击“更新”按钮,把修改后的数据保存到数据库中,同时与Listview联动. 第一步.建立一个WPF项目

WPF入门教程系列(二) 深入剖析WPF Binding的使用方法

WPF入门教程系列(二) 深入剖析WPF Binding的使用方法 同一个对象(特指System.Windows.DependencyObject的子类)的同一种属性(特指DependencyProperty)只能拥有一个binding. 这一点可以通过设置binding对象的方法名得知: public static BindingExpressionBase SetBinding( DependencyObject target, DependencyProperty dp, BindingB

WPF入门教程系列二——Application介绍

原文:WPF入门教程系列二--Application介绍 一.Application介绍 WPF和WinForm 很相似, WPF与WinForm一样有一个 Application对象来进行一些全局的行为和操作,并且每个 Domain (应用程序域)中仅且只有一个 Application 实例存在.和 WinForm 不同的是WPF Application默认由两部分组成 : App.xaml 和 App.xaml.cs,这有点类似于 Asp.Net WebForm,将定义和行为代码相分离. 微

SeaJS入门教程系列之使用SeaJS(二)

SeaJS入门教程系列之使用SeaJS(二) 作者: 字体:[增加 减小] 类型:转载 时间:2014-03-03我要评论 这篇文章主要介绍了SeaJS入门教程系列之使用SeaJS,着重介绍了SeaJS的使用方法.关键方法的使用等,需要的朋友可以参考下 下载及安装 要在项目中使用SeaJS,你所有需要做的准备工作就是下载sea.js然后放到你项目的某个位置.SeaJS项目目前托管在GitHub上,主页为 https://github.com/seajs/seajs/ .可以到其git库的buil

[转载]WPF入门教程系列一——基础

一. 前言   最近在学习WPF,学习WPF首先上的是微软的MSDN,然后再搜索了一下网络有关WPF的学习资料.为了温故而知新把学习过程记录下来,以备后查.这篇主要讲WPF的开发基础,介绍了如何使用Visual Studio 2013创建一个WPF应用程序. 首先说一下学习WPF的基础知识: 1) 要会一门.NET所支持的编程语言.例如C#. 2) 会一点“标准通用标记语言”:WPF窗体程序使用的XAML语言,也属于“标准通用标记语言”的一个分支.如果以前接触过XML.HTML.XHTML.AS