Proprietà di caricamento e dipendenza XAML (WPF .NET)

L'implementazione di Windows Presentation Foundation (WPF) del processore XAML (Extensible Application Markup Language) è intrinsecamente compatibile con la proprietà di dipendenza. Di conseguenza, il processore XAML usa metodi di sistema di proprietà WPF per caricare gli attributi delle proprietà di dipendenza XAML ed elaborare gli attributi delle proprietà di dipendenza e ignora completamente i wrapper delle proprietà di dipendenza usando metodi del sistema di proprietà WPF come GetValue e SetValue. Quindi, se aggiungi logica personalizzata al wrapper della proprietà della proprietà di dipendenza personalizzata, non verrà chiamata dal processore XAML quando un valore della proprietà viene impostato in XAML.

Importante

La documentazione di Desktop Guide per .NET 7 e .NET 6 è in fase di costruzione.

Prerequisiti

L'articolo presuppone una conoscenza di base delle proprietà di dipendenza e che si abbia letto Panoramica delle proprietà di dipendenza. Per seguire gli esempi in questo articolo, è utile se si ha familiarità con Extensible Application Markup Language (XAML) e si sa come scrivere applicazioni WPF.

Prestazioni del caricatore XAML WPF

È meno costoso per il processore XAML WPF chiamare SetValue direttamente per impostare il valore di una proprietà di dipendenza anziché usare il wrapper della proprietà di una proprietà di dipendenza.

Se il processore XAML usa il wrapper della proprietà, sarebbe necessario dedurre l'intero modello a oggetti del codice di supporto in base solo alle relazioni tra tipo e membro indicate nel markup. Anche se il tipo può essere identificato dal markup usando una combinazione di attributi di xmlns assembly e , identificando i membri, determinando quali membri possono essere impostati come attributo e risolvendo i tipi di valore di proprietà supportati, richiederebbe una reflection estesa usando PropertyInfo.

Il sistema di proprietà WPF gestisce una tabella di archiviazione delle proprietà di dipendenza implementata in un determinato DependencyObject tipo derivato. Il processore XAML usa tale tabella per dedurre l'identificatore della proprietà di dipendenza per una proprietà di dipendenza. Ad esempio, per convenzione, l'identificatore della proprietà di dipendenza per una proprietà di dipendenza denominata ABC è ABCProperty. Il processore XAML può impostare in modo efficiente il valore di qualsiasi proprietà di dipendenza chiamando il SetValue metodo sul tipo contenitore usando l'identificatore della proprietà di dipendenza.

Per altre informazioni sui wrapper delle proprietà di dipendenza, vedere Proprietà di dipendenza personalizzate.

Implicazioni per le proprietà di dipendenza personalizzate

Il processore XAML WPF ignora i wrapper delle proprietà e chiama SetValue direttamente per impostare un valore della proprietà di dipendenza. Evitare quindi di inserire qualsiasi logica aggiuntiva nella set funzione di accesso della proprietà di dipendenza personalizzata perché tale logica non verrà eseguita quando viene impostato un valore di proprietà in XAML. La set funzione di accesso deve contenere solo una SetValue chiamata.

Analogamente, gli aspetti del processore XAML WPF che ottengono i valori delle proprietà ignorano il wrapper della proprietà e chiamano GetValuedirettamente . Evitare quindi di inserire qualsiasi logica aggiuntiva nella get funzione di accesso della proprietà di dipendenza personalizzata perché tale logica non verrà eseguita quando un valore della proprietà viene letto in XAML. La get funzione di accesso deve contenere solo una GetValue chiamata.

Esempio di proprietà di dipendenza con wrapper

L'esempio seguente mostra una definizione di proprietà di dipendenza consigliata con wrapper di proprietà. L'identificatore della proprietà di dipendenza viene archiviato come public static readonly campo e le get funzioni di accesso e set non contengono codice oltre i metodi del sistema di proprietà WPF necessari che eseguono il backup del valore della proprietà di dipendenza. Se si dispone di codice che deve essere eseguito quando viene modificato il valore della proprietà di dipendenza, è consigliabile inserire tale codice in per la PropertyChangedCallback proprietà di dipendenza. Per altre informazioni, vedere Callback delle proprietà modificate.

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

Vedi anche