XAML 載入和相依性屬性 (WPF .NET)

其 Extensible Application Markup Language (XAML) 處理器的 Windows Presentation Foundation (WPF) 實作原本就是相依性屬性感知。 因此,XAML 處理器會使用 WPF 屬性系統方法來載入 XAML 和處理相依性屬性屬性,並使用 和 SetValueGetValue WPF 屬性系統方法完全略過相依性屬性包裝函式。 因此,如果您將自訂邏輯新增至自訂相依性屬性的屬性包裝函式,在 XAML 中設定屬性值時,XAML 處理器將不會呼叫它。

重要

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

必要條件

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

WPF XAML 載入器效能

WPF XAML 處理器直接呼叫 SetValue 以設定相依性屬性的值,而不是使用相依性屬性的屬性包裝函式,其計算成本較低。

如果 XAML 處理器確實使用屬性包裝函式,它只需要根據標記中所指出的類型和成員關聯性來推斷備份程式碼的整個物件模型。 雖然型別可以使用 和 元件屬性的組合 xmlns 來識別標記,但識別成員、判斷哪些成員可以設定為屬性,以及解析支援的屬性值類型,都需要使用 PropertyInfo 廣泛反映。

WPF 屬性系統會維護在指定 DependencyObject 衍生類型上實作之相依性屬性的儲存資料表。 XAML 處理器使用該資料表來推斷相依性屬性的相依性屬性識別碼。 例如,依慣例,名為 ABC 之相依性屬性的相依性屬性識別碼為 ABCProperty 。 XAML 處理器可以使用相依性屬性識別碼,在其包含類型上呼叫 SetValue 方法,以有效率地設定任何相依性屬性的值。

如需相依性屬性包裝函式的詳細資訊,請參閱 自訂相依性屬性

自訂相依性屬性的影響

WPF XAML 處理器會略過屬性包裝函式,並直接呼叫 SetValue 以設定相依性屬性值。 因此,請避免將任何額外的邏輯放在自訂相依性屬性的存取子中 set ,因為該邏輯不會在 XAML 中設定屬性值時執行。 存取 set 子應該只包含 SetValue 呼叫。

同樣地,取得屬性值的 WPF XAML 處理器層面會略過屬性包裝函式並直接呼叫 GetValue 。 因此,也請避免將任何額外的邏輯 get 放在自訂相依性屬性的存取子中,因為該邏輯在 XAML 中讀取屬性值時不會執行。 存取 get 子應該只包含 GetValue 呼叫。

含包裝函式範例的相依性屬性

下列範例顯示具有屬性包裝函式的建議相依性屬性定義。 相依性屬性識別碼會儲存為 public static readonly 欄位,且 getset 存取子不包含超過可備份相依性屬性值的必要 WPF 屬性系統方法以外的程式碼。 如果您有需要在相依性屬性的值變更時執行的程式碼,請考慮將該程式碼放入相依性屬性的 PropertyChangedCallback 中。 如需詳細資訊,請參閱 屬性變更回 呼。

// Register a dependency property with the specified property name,
// property type, owner type, and property metadata. Store the dependency
// property identifier as a public static readonly member of the class.
public static readonly DependencyProperty AquariumGraphicProperty =
    DependencyProperty.Register(
      name: "AquariumGraphic",
      propertyType: typeof(Uri),
      ownerType: typeof(Aquarium),
      typeMetadata: new FrameworkPropertyMetadata(
          defaultValue: new Uri("http://www.contoso.com/aquarium-graphic.jpg"),
          flags: FrameworkPropertyMetadataOptions.AffectsRender,
          propertyChangedCallback: new PropertyChangedCallback(OnUriChanged))
    );

// Property wrapper with get & set accessors.
public Uri AquariumGraphic
{
    get => (Uri)GetValue(AquariumGraphicProperty);
    set => SetValue(AquariumGraphicProperty, value);
}

// Property-changed callback.
private static void OnUriChanged(DependencyObject dependencyObject, 
    DependencyPropertyChangedEventArgs e)
{
    // Some custom logic that runs on effective property value change.
    Uri newValue = (Uri)dependencyObject.GetValue(AquariumGraphicProperty);
    Debug.WriteLine($"OnUriChanged: {newValue}");
}
' Register a dependency property with the specified property name,
' property type, owner type, and property metadata. Store the dependency
' property identifier as a public static readonly member of the class.
Public Shared ReadOnly AquariumGraphicProperty As DependencyProperty =
    DependencyProperty.Register(
        name:="AquariumGraphic",
        propertyType:=GetType(Uri),
        ownerType:=GetType(Aquarium),
        typeMetadata:=New FrameworkPropertyMetadata(
            defaultValue:=New Uri("http://www.contoso.com/aquarium-graphic.jpg"),
            flags:=FrameworkPropertyMetadataOptions.AffectsRender,
            propertyChangedCallback:=New PropertyChangedCallback(AddressOf OnUriChanged)))

' Property wrapper with get & set accessors.
Public Property AquariumGraphic As Uri
    Get
        Return CType(GetValue(AquariumGraphicProperty), Uri)
    End Get
    Set
        SetValue(AquariumGraphicProperty, Value)
    End Set
End Property

' Property-changed callback.
Private Shared Sub OnUriChanged(dependencyObject As DependencyObject,
                                e As DependencyPropertyChangedEventArgs)
    ' Some custom logic that runs on effective property value change.
    Dim newValue As Uri = CType(dependencyObject.GetValue(AquariumGraphicProperty), Uri)
    Debug.WriteLine($"OnUriChanged: {newValue}")
End Sub

另請參閱