Propriedades de carregamento e dependência de XAML (WPF .NET)
A implementação do Windows Presentation Foundation (WPF) de seu processador XAML (Extensible Application Markup Language) é inerentemente ciente da propriedade de dependência. Assim, o processador XAML usa métodos do sistema de propriedades WPF para carregar XAML e processar atributos de propriedade de dependência, ignorando completamente os involucros de propriedade de dependência ao usar métodos do sistema de propriedades WPF como GetValue e SetValue. Portanto, se adicionares código personalizado ao invólucro de propriedade da tua propriedade de dependência personalizada, ele não será chamado pelo processador XAML quando um valor de propriedade for definido em XAML.
Pré-requisitos
O artigo pressupõe um conhecimento básico das propriedades de dependência e que você leu Visão geral das propriedades de dependência. Para seguir os exemplos neste artigo, isso ajuda se você estiver familiarizado com Extensible Application Markup Language (XAML) e souber como escrever aplicativos WPF.
Desempenho do carregador WPF XAML
É computacionalmente mais barato para o processador WPF XAML chamar diretamente SetValue para atribuir o valor de uma propriedade de dependência, ao invés de usar o invólucro de uma propriedade de dependência.
Se o processador XAML usasse o envoltório de propriedade, seria necessário inferir todo o modelo de objeto do código subjacente com base apenas nas relações de tipo e membro indicadas na marcação. Embora o tipo possa ser identificado a partir da marcação usando uma combinação de atributos xmlns
e assembly, identificar os membros, determinar quais membros podem ser definidos como um atributo e resolver tipos de valor de propriedade suportados exigiria uma reflexão extensiva usando PropertyInfo.
O sistema de propriedades WPF mantém uma tabela de armazenamento de propriedades de dependência implementadas em um determinado tipo derivado de DependencyObject. O processador XAML usa essa tabela para inferir o identificador da propriedade de dependência. Por exemplo, por convenção, o identificador de propriedade de dependência para uma propriedade de dependência chamada ABC
é ABCProperty
. O processador XAML pode definir eficientemente o valor de qualquer propriedade de dependência chamando o método SetValue
em seu tipo de contenção usando o identificador de propriedade de dependência.
Para mais informações sobre invólucros de propriedades de dependência, consulte Propriedades de dependência personalizadas.
Implicações para propriedades de dependência personalizadas
O processador WPF XAML ignora os envoltórios de propriedades e chama diretamente SetValue para definir o valor de uma propriedade de dependência. Portanto, evite colocar qualquer lógica extra no acessador de set
de sua propriedade de dependência personalizada porque essa lógica não será executada quando um valor de propriedade for definido em XAML. O acessor de set
deve conter apenas uma chamada de SetValue
.
Da mesma forma, os aspetos do processador WPF XAML que obtêm valores de propriedade ignoram o envoltório de propriedade e invocam diretamente GetValue. Portanto, evite também colocar qualquer lógica extra no acessor get
da sua propriedade de dependência personalizada, pois essa lógica não será executada quando o valor da propriedade é lido em XAML. O acessador de get
deve conter apenas uma chamada GetValue
.
Propriedade de dependência com exemplo de wrapper
O exemplo a seguir apresenta uma definição de propriedade de dependência recomendada com contornadores de propriedade. O identificador de propriedade de dependência é armazenado como um campo public static readonly
e os acessadores de get
e set
não contêm nenhum código além dos métodos necessários do sistema de propriedades WPF que apoiam o valor da propriedade de dependência. Se você tiver um código que precisa ser executado quando o valor da sua propriedade de dependência for alterado, considere colocar esse código no PropertyChangedCallback da sua propriedade de dependência. Para obter mais informações, consulte Retornos de chamada alterados de propriedade.
// 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
Ver também
.NET Desktop feedback