WPF入門教程系列十二——依賴屬性(二)

2、 依賴屬性的優先級編程

  因爲WPF 容許咱們能夠在多個地方設置依賴屬性的值,因此咱們就必需要用一個標準來保證值的優先級別。好比下面的例子中,咱們在三個地方設置了按鈕的背景顏色,那麼哪個設置纔會是最終的結果呢?是Black、Red仍是Azure呢?windows

 

<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>

 

 

 

經過前面的簡單介紹,咱們瞭解了簡單的依賴屬性,每次訪問一個依賴屬性,它內部會按照下面的順序由高到底處理該值。詳細見下圖app

  

  因爲這個流程圖偏理想化,在實際的工做過程當中咱們會遇到各類各樣的問題,我也不可能都碰到,也就沒法完全把這些問題說清楚,因此當咱們遇到問題以後,再進行仔細分析,查找緣由,不斷總結、觸類旁通。oop

3、 依賴屬性的繼承性能

  屬性值繼承是 Windows Presentation Foundation (WPF) 屬性系統的一項功能。 屬性值繼承使元素樹中的子元素能夠從父元素那裏獲取特定屬性的值,並繼承該值,就好像它是在最近的父元素中的任意位置設置的同樣。 父元素還能夠經過屬性值繼承來得到其值,所以系統有可能一直遞歸到頁面根元素。 屬性值繼承不是屬性系統的默認行爲;屬性必須用特定的元數據設置來創建,以便使該屬性可以對子元素啓動屬性值繼承。字體

 

依賴屬性繼承的最初意願是父元素的相關設置會自動傳遞給全部層次的子元素 ,即元素能夠從其在樹中的父級繼承依賴項屬性的值。這個咱們在編程當中接觸得比較多,如當咱們修改窗體父容器控件的字體設置時,全部級別的子控件都將自動 使用該字體設置 (前提是該子控件未作自定義設置)。接下來,咱們來作一個實際的例子。代碼以下:this

<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>

 

代碼spa

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,因此這個時候繼承的值就不會再起做用了。code

  這個時候你會發現一個很奇怪的問題:雖然StatusBar沒有重寫FontSize,同時它也是Window的子元素,可是它的字體大小卻沒 有變化,保持了系統默認值。那這是什麼緣由呢?做爲初學者可能都很納悶,官方不是說了原則是這樣的,爲何會出現表裏不一的狀況呢?其實仔細研究才發現並 不是全部的元素都支持屬性值繼承。還會存在一些意外的狀況,那麼總的來講是因爲如下兩個方面:

一、有些Dependency屬性在用註冊的時候時指定Inherits爲不可繼承,這樣繼承就會失效了。

二、有其餘更優先級的設置設置了該值,在前面講的的「依賴屬性的優先級」你能夠看到具體的優先級別。

屬性值繼承經過混合樹操做。持有原始值的父對象和繼承該值的子對象都必須是 FrameworkElementFrameworkContentElement,且都必須屬於某個邏輯樹。 可是,對於支持屬性繼承的現有 WPF 屬性,屬性值的繼承可以經過邏輯樹中沒有的中介對象永久存在。 這主要適用於如下狀況:讓模板元素使用在應用了模板的實例上設置的全部繼承屬性值,或者使用在更高級別的頁級成分(所以在邏輯樹中也位於更高位置)中設置的全部繼承屬性值。 爲了使屬性值的繼承在這兩種狀況下保持一致,繼承屬性必須註冊爲附加屬性。

  這裏的緣由是部分控件如StatusBar、Tooptip和Menu等內部設置它們的字體屬性值以匹配當前系統。這樣用戶經過操做系統的控制 面板來修改它們的外觀。這種方法存在一個問題:StatusBar等截獲了從父元素繼承來的屬性,而且不影響其子元素。好比,若是咱們在 StatusBar中添加了一個Button。那麼這個Button的字體屬性會由於StatusBar的截斷而沒有任何改變,將保留其默認值。因此你們 在使用的時候要特別注意這些問題。

相關文章
相關標籤/搜索