Proprietà di caricamento e dipendenza XAML (WPF .NET)
L'implementazione di Windows Presentation Foundation (WPF) del processore XAML (Extensible Application Markup Language) è intrinsecamente sensibile alle proprietà di dipendenza. Di conseguenza, il processore XAML utilizza i metodi del sistema di proprietà WPF per caricare XAML e gestire gli attributi delle proprietà di dipendenza, bypassando 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 tua proprietà di dipendenza personalizzata, non verrà chiamata dal processore XAML quando un valore della proprietà viene impostato in XAML.
Prerequisiti
L'articolo presuppone una conoscenza di base delle proprietà di dipendenza e che tu 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 computazionalmente per il processore XAML WPF chiamare direttamente SetValue per impostare il valore di una proprietà di dipendenza, anziché utilizzare l'involucro della proprietà di una proprietà di dipendenza.
Se il processore XAML avesse utilizzato il wrapper della proprietà, sarebbe stato necessario dedurre l'intero modello a oggetti del codice sottostante basandosi solo sulle relazioni di tipo e membro indicate nel markup. Anche se il tipo può essere identificato dal markup usando una combinazione di attributi di xmlns
e assembly, l'identificazione dei membri, la determinazione di quali possono essere impostati come attributi e la risoluzione dei tipi di valore delle proprietà supportati richiederebbero una riflessione estesa usando PropertyInfo.
Il sistema di proprietà WPF gestisce una tabella di memorizzazione delle proprietà di dipendenza implementate su un determinato tipo derivato DependencyObject. 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 è in grado di impostare efficacemente il valore di qualsiasi proprietà dipendente chiamando il metodo SetValue
sul tipo contenitore utilizzando l'identificatore della proprietà dipendente.
Per ulteriori 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 direttamente SetValue per impostare un valore della proprietà di dipendenza. Evitare quindi di inserire qualsiasi logica aggiuntiva nella funzione di accesso set
della proprietà di dipendenza personalizzata perché tale logica non verrà eseguita quando un valore di proprietà viene impostato in XAML. L'accessor set
dovrebbe contenere soltanto una chiamata SetValue
.
Analogamente, gli aspetti del processore WPF XAML che ottengono i valori delle proprietà ignorano il wrapper della proprietà e chiamano direttamente GetValue. Evitare quindi di inserire qualsiasi logica aggiuntiva nella funzione di accesso get
della proprietà di dipendenza personalizzata perché tale logica non verrà eseguita quando un valore della proprietà viene letto in XAML. L'accessor get
deve contenere solo una chiamata GetValue
.
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 campo di public static readonly
e gli accessor get
e set
non contengono codice oltre ai metodi necessari del sistema di proprietà WPF che supportano il valore della proprietà di dipendenza. Se hai del codice che deve essere eseguito quando viene modificato il valore della tua proprietà di dipendenza, considera di inserire quel codice nella PropertyChangedCallback per la tua 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
Vedere anche
.NET Desktop feedback