屬性值繼承 (WPF .NET)

屬性值繼承是 Windows Presentation Foundation (WPF) 屬性系統的功能,並套用至相依性屬性。 屬性值繼承可讓專案樹狀結構中的子專案從最接近的父元素取得特定屬性的值。 由於父元素可能也已透過屬性值繼承取得其屬性值,因此系統可能會遞迴回頁面根目錄。

WPF 屬性系統預設不會啟用屬性值繼承,除非相依性屬性 中繼資料 中特別啟用,否則值繼承為非使用中。 即使啟用屬性值繼承,子項目只會在缺少較高 優先順序 值的情況下繼承屬性值。

重要

.NET 7 和 .NET 6 的桌面指南檔正在建置中。

必要條件

本文假設您具備相依性屬性的基本知識,而且您已閱讀 相依性屬性概觀 。 若要遵循本文中的範例,如果您熟悉可延伸的應用程式標記語言(XAML),並知道如何撰寫 WPF 應用程式,它很有説明。

透過專案樹狀結構繼承

屬性值繼承與物件導向程式設計中的類別繼承概念不同,其中衍生類別繼承基類成員。 雖然在 XAML 中,繼承的基類屬性會公開為代表衍生類別之 XAML 元素的屬性,但這種繼承在 WPF 中也是作用中的。

屬性值繼承是相依性屬性值從父元素傳播到包含 屬性之專案樹狀結構內的子專案的機制。 在 XAML 標記中,元素的樹狀結構會顯示為巢狀專案。

下列範例示範 XAML 中的巢狀專案。 WPF 會在 AllowDrop 類別上 UIElement 向屬性 中繼資料 註冊相依性屬性,以啟用屬性值 繼承 ,並將預設值設定為 false 。 相 AllowDrop 依性屬性存在於 、 StackPanelLabel 元素上 Canvas ,因為它們都是衍生自 UIElement 。 由於 上的 AllowDropcanvas1 相依性屬性設定為 true ,因此子 stackPanel1 代和 label1 元素會繼承 true 為其 AllowDrop 值。

<Canvas x:Name="canvas1" Grid.Column="0" Margin="20" Background="Orange" AllowDrop="True">
    <StackPanel Name="stackPanel1" Margin="20" Background="Green">
        <Label Name="label1" Margin="20" Height="40" Width="40" Background="Blue"/>
    </StackPanel>
</Canvas>

您也可以透過程式設計方式建立專案的樹狀結構,方法是將專案物件新增至另一個元素物件的子專案集合。 在執行時間,屬性值繼承會在結果物件樹狀結構上運作。 在下列範例中, stackPanel2 會新增至 canvas2 子集合 。 同樣地,會 label2 新增至 的 stackPanel2 子集合。 由於 上的 AllowDropcanvas2 相依性屬性設定為 true ,因此子 stackPanel2 代和 label2 元素會繼承 true 為其 AllowDrop 值。

Canvas canvas2 = new()
{
    AllowDrop = true
};
StackPanel stackPanel2 = new();
Label label2 = new();
canvas2.Children.Add(stackPanel2);
stackPanel2.Children.Add(label2);
Dim canvas2 As New Canvas With {
    .AllowDrop = True
}
Dim stackPanel2 As New StackPanel()
Dim label2 As New Label()
canvas2.Children.Add(stackPanel2)
stackPanel2.Children.Add(label2)

屬性值繼承的實際應用

特定的 WPF 相依性屬性預設會啟用值繼承,例如 AllowDropFlowDirection 。 一般而言,預設啟用值繼承的屬性會在基底 UI 元素類別上實作,因此它們存在於衍生類別上。 例如,由於 AllowDrop 是在基類上 UIElement 實作,因此相依性屬性也存在於衍生自 UIElement 的每個控制項上。 WPF 可讓使用者在父元素上設定屬性值一次,並讓該屬性值傳播至元素樹狀結構中的子系元素,而 WPF 可對相依性屬性啟用值繼承。

屬性值繼承模型會根據 相依性屬性值優先順序 ,指派繼承和未繼承的屬性值。 因此,如果子項目屬性沒有較高的優先順序值,例如本機設定值,或透過樣式、範本或資料系結取得的值,父元素屬性值才會套用至子項目。

FlowDirection 依性屬性會設定父元素內文字和子 UI 元素的配置方向。 一般而言,您會預期頁面內的文字和 UI 元素流程方向一致。 由於 值繼承是在 的屬性 FlowDirection 中繼資料 中啟用,因此值只需要在頁面的專案樹狀結構頂端設定一次。 在極少數情況下,混合流程方向適用于頁面,您可以藉由指派本機設定值,在樹狀結構中的元素上設定不同的流程方向。 新的流程方向接著會傳播到該層級以下的子代元素。

將自訂屬性設為可繼承

您可以在 的 FrameworkPropertyMetadata 實例中啟用 Inherits 屬性,然後向該中繼資料實例註冊自訂相依性屬性,讓自訂相依性屬性可繼承。 根據預設,在 中 FrameworkPropertyMetadata 設定 Inheritsfalse 。 將屬性值設為可繼承會影響效能,因此只有在需要該功能時才會設定 Inheritstrue

當您在中繼資料中註冊已啟用的 Inherits 相依性屬性時,請使用 RegisterAttached 方法,如註冊附加屬性 中所述 。 此外,將預設值指派給 屬性,讓可繼承的值存在。 您可能也想要在擁有者類型上建立具有 getset 存取子的屬性包裝函式,就像對非附加的相依性屬性一樣。 如此一來,您就可以在擁有者或衍生類型上使用屬性包裝函式來設定屬性值。 下列範例會建立名為 IsTransparent 的相依性屬性,並 Inherits 啟用 且預設值為 false 。 此範例也包含具有 getset 存取子的屬性包裝函式。

public class Canvas_IsTransparentInheritEnabled : Canvas
{
    // Register an attached dependency property with the specified
    // property name, property type, owner type, and property metadata
    // (default value is 'false' and property value inheritance is enabled).
    public static readonly DependencyProperty IsTransparentProperty =
        DependencyProperty.RegisterAttached(
            name: "IsTransparent",
            propertyType: typeof(bool),
            ownerType: typeof(Canvas_IsTransparentInheritEnabled),
            defaultMetadata: new FrameworkPropertyMetadata(
                defaultValue: false,
                flags: FrameworkPropertyMetadataOptions.Inherits));

    // Declare a get accessor method.
    public static bool GetIsTransparent(Canvas element)
    {
        return (bool)element.GetValue(IsTransparentProperty);
    }

    // Declare a set accessor method.
    public static void SetIsTransparent(Canvas element, bool value)
    {
        element.SetValue(IsTransparentProperty, value);
    }

    // For convenience, declare a property wrapper with get/set accessors.
    public bool IsTransparent
    {
        get => (bool)GetValue(IsTransparentProperty);
        set => SetValue(IsTransparentProperty, value);
    }
}
Public Class Canvas_IsTransparentInheritEnabled
    Inherits Canvas

    ' Register an attached dependency property with the specified
    ' property name, property type, owner type, and property metadata
    ' (default value is 'false' and property value inheritance is enabled).
    Public Shared ReadOnly IsTransparentProperty As DependencyProperty =
        DependencyProperty.RegisterAttached(
            name:="IsTransparent",
            propertyType:=GetType(Boolean),
            ownerType:=GetType(Canvas_IsTransparentInheritEnabled),
            defaultMetadata:=New FrameworkPropertyMetadata(
                defaultValue:=False,
                flags:=FrameworkPropertyMetadataOptions.[Inherits]))

    ' Declare a get accessor method.
    Public Shared Function GetIsTransparent(element As Canvas) As Boolean
        Return element.GetValue(IsTransparentProperty)
    End Function

    ' Declare a set accessor method.
    Public Shared Sub SetIsTransparent(element As Canvas, value As Boolean)
        element.SetValue(IsTransparentProperty, value)
    End Sub

    ' For convenience, declare a property wrapper with get/set accessors.
    Public Property IsTransparent As Boolean
        Get
            Return GetValue(IsTransparentProperty)
        End Get
        Set(value As Boolean)
            SetValue(IsTransparentProperty, value)
        End Set
    End Property
End Class

附加屬性在概念上類似于全域屬性。 您可以在任何 DependencyObject 上檢查其值,並取得有效的結果。 附加屬性的一般案例是在子項目上設定屬性值,如果有問題的 屬性隱含呈現為樹狀結構中每個 DependencyObject 元素的附加屬性,則此案例會更有效率。

跨樹狀界限繼承屬性值

屬性繼承的運作方式是周遊元素的樹狀結構。 此樹狀結構通常會與邏輯樹狀結構平行。 不過,當您在定義專案樹狀結構的標記中包含 WPF 核心層級物件,例如 Brush ,您已建立不連續的邏輯樹狀結構。 真正的邏輯樹狀結構在概念上不會透過 Brush 延伸,因為邏輯樹狀結構是 WPF 架構層級的概念。 您可以使用 的 LogicalTreeHelper 協助程式方法來分析和檢視邏輯樹狀結構的範圍。 屬性值繼承可以透過不連續的邏輯樹狀結構傳遞繼承值,但只有在可繼承的屬性註冊為附加屬性,而且沒有刻意的繼承封鎖界限,例如 Frame

注意

雖然屬性值繼承可能適用于未附加的相依性屬性,但未定義執行時間樹狀結構中某些元素界限的非附加屬性繼承行為。 每當您在屬性中繼資料中指定 Inherits 時,請使用 RegisterAttached 註冊屬性。

另請參閱