Propriedades de carregamento e dependência XAML (WPF .NET)

A implementação do Windows Presentation Foundation (WPF) de seu processador XAML (Extensible Application Markup Language) reconhece inerentemente a propriedade de dependência. Como tal, o processador XAML usa métodos de sistema de propriedades WPF para carregar atributos de propriedade de dependência de processo e XAML e ignora totalmente os wrappers de propriedade de dependência usando métodos de 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.

Importante

A documentação do Guia da Área de Trabalho para .NET 7 e .NET 6 está em construção.

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, é útil se você estiver familiarizado com XAML (Extensible Application Markup Language) e souber como escrever aplicativos WPF.

Desempenho do carregador XAML do WPF

É computacionalmente mais barato para o processador XAML WPF chamar SetValue diretamente para definir o valor de uma propriedade de dependência, em vez de usar o wrapper de propriedade de uma propriedade de dependência.

Se o processador XAML usasse o wrapper de propriedades, seria necessário inferir todo o modelo de objeto do código de suporte 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 e assembly, identificar os membros, determinar quais membros podem ser definidos como um atributo e resolver tipos de valor de xmlns propriedade com suporte exigiria uma reflexão extensiva usando PropertyInfoo .

O sistema de propriedades 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 propriedade de dependência para uma propriedade de dependência. Por exemplo, por convenção, o identificador da propriedade de dependência para uma propriedade de dependência nomeada ABC é ABCProperty. O processador XAML pode definir eficientemente o valor de qualquer propriedade de dependência chamando o método em seu tipo de contenção usando o SetValue identificador de propriedade de dependência.

Para obter mais informações sobre wrappers de propriedades de dependência, consulte Propriedades de dependência personalizadas.

Implicações para propriedades de dependência personalizadas

O processador XAML do WPF ignora wrappers de propriedade 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, pois 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, os aspectos do processador XAML do WPF que obtêm valores de propriedade ignoram o wrapper de propriedade e chamam GetValuediretamente . Portanto, evite também colocar qualquer lógica extra no get acessador de sua propriedade de dependência personalizada, pois essa lógica não será executada quando um valor de propriedade for lido em XAML. O get acessador deve conter apenas uma GetValue chamada.

Propriedade de dependência com exemplo de wrapper

O exemplo a seguir mostra uma definição de propriedade de dependência recomendada com wrappers de propriedade. O identificador de propriedade de dependência é armazenado como um campo, e os getset e acessadores não contêm nenhum código além dos métodos de sistema de propriedade WPF necessários que dão suporte ao valor da propriedade de public static readonly dependência. Se você tiver código que precisa ser executado quando o valor da propriedade de dependência for alterado, considere colocar esse código na PropertyChangedCallback propriedade for for the dependency. Para obter mais informações, consulte Retornos de chamada alterados por 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

Confira também