Compartilhar via


Carregamento de XAML e propriedades de dependência

A implementação do WPF (Windows Presentation Foundation) de seu processador XAML (Extensible Application Markup Language) é inerentemente consciente da propriedade de dependência. Assim, o processador XAML usa métodos do sistema de propriedades WPF para carregar XAML e processar atributos de propriedades de dependência, ignorando totalmente os wrappers de propriedade de dependência ao usar métodos do sistema de propriedades WPF como GetValue e SetValue. Portanto, se você adicionar lógica personalizada ao wrapper de propriedade de sua propriedade de dependência personalizada, ela não será chamada 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, ele ajuda se você estiver familiarizado com XAML (Extensible Application Markup Language) e saber como escrever aplicativos WPF.

Desempenho do carregador XAML do WPF

É computacionalmente menos dispendioso para o processador XAML do WPF chamar SetValue diretamente para definir o valor de uma propriedade de dependência, em vez de usar o invólucro da propriedade de uma propriedade de dependência.

Se o processador XAML usasse o empacotador de propriedade, requereria inferir todo o modelo de objetos do código subjacente com base apenas nas relações de tipo e membro indicadas na marcação. Embora o tipo possa ser identificado por meio da marcação usando uma combinação de xmlns e atributos de assembly, identificar os membros, determinar quais membros podem ser definidos como um atributo e resolver tipos de valor de propriedade com suporte exigiria uma reflexão abrangente usando PropertyInfo.

O sistema de propriedades do WPF mantém uma tabela de armazenamento de propriedades de dependência implementadas em um determinado DependencyObject tipo derivado. O processador XAML usa essa tabela para inferir o identificador de uma propriedade de dependência. Por exemplo, por convenção, o identificador de propriedade de dependência para uma propriedade de dependência nomeada ABC é ABCProperty. O processador XAML pode definir com eficiência o valor de qualquer propriedade de dependência chamando o SetValue método em seu tipo de contenção usando o identificador de propriedade de dependência.

Para obter mais informações sobre envoltórios de propriedade de dependência, consulte Propriedades de dependência definidas pelo usuário.

Implicações para propriedades de dependência personalizadas

O processador XAML do WPF ignora os envoltórios de propriedades e chama SetValue diretamente para definir um valor de propriedade de dependência. Portanto, evite colocar qualquer lógica extra no set acessador 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 set acessador deve conter apenas uma SetValue chamada.

Da mesma forma, aspectos do processador XAML do WPF que obtêm valores de propriedade ignoram o wrapper de propriedade e chamam GetValue diretamente. Evite, portanto, colocar qualquer lógica extra no get acessador de sua propriedade de dependência personalizada, pois essa lógica não irá funcionar quando um valor de propriedade for lido no XAML. O get acessador deve conter apenas uma GetValue chamada.

Propriedade de dependência com exemplo de encapsulamento

O exemplo a seguir mostra uma definição recomendada de propriedade de dependência com encapsuladores de propriedade. O identificador da propriedade de dependência é armazenado como um public static readonly campo, e os acessadores get e set não contêm nenhum código além dos métodos necessários do sistema de propriedades WPF que sustentam o valor da propriedade de dependência. Se você tiver um código que precisa ser executado quando o valor da propriedade de dependência for alterado, considere colocar esse código no método PropertyChangedCallback associado à sua propriedade de dependência. Para obter mais informações, consulte Callbacks para alteração 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

Consulte também