Compartilhar via


Carregamento XAML e propriedades de dependência (WPF .NET)

A implementação do Windows Presentation Foundation (WPF) de seu processador XAML (Extensible Application Markup Language) é inerentemente sensível à propriedade de dependência. Dessa forma, o processador XAML usa métodos do sistema de propriedades do WPF para carregar atributos de propriedade de dependência XAML e processar e ignora totalmente os wrappers de propriedade de dependência usando métodos do sistema de propriedades do 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, é ú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 do 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 propriedade, 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 de montagem e , identificar os membros, determinar quais membros podem ser definidos como um atributo e resolver tipos de xmlns valor de propriedade com suporte exigiria uma reflexão extensa 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 propriedade de dependência para uma 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 com eficiência o valor de qualquer propriedade de dependência chamando o SetValue método em seu tipo de conteúdo usando o identificador de propriedade de dependência.

Para obter mais informações sobre wrappers de propriedade 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, 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 acessador de sua propriedade de dependência personalizada, pois essa lógica não será executada quando um valor de propriedade for lido get 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 public static readonly campo e os get acessadores and set não contêm nenhum código além dos métodos necessários do sistema de propriedades do WPF que dão suporte ao valor da propriedade de dependência. Se você tiver um código que precise ser executado quando o valor da propriedade de dependência for alterado, considere colocar esse código na PropertyChangedCallback propriedade de dependência. Para obter mais informações, consulte Retornos de chamada com 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

Confira também