Visão geral das propriedades anexadas (WPF .NET)

Uma propriedade anexada é um conceito XAML (Extensible Application Markup Language). As propriedades anexadas permitem que pares de propriedade/valor extras sejam definidos em qualquer elemento XAML derivado do , mesmo que o elemento não defina essas propriedades extras em seu modelo de DependencyObjectobjeto. As propriedades extras são acessíveis globalmente. As propriedades anexadas são normalmente definidas como uma forma especializada de propriedade de dependência que não tem um wrapper de propriedade convencional.

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 e souber como escrever aplicativos Windows Presentation Foundation (WPF).

Por que usar propriedades anexadas

Uma propriedade anexada permite que um elemento filho especifique um valor exclusivo para uma propriedade definida em um elemento pai. Um cenário comum é um elemento filho especificando como ele deve ser renderizado na interface do usuário por seu elemento pai. Por exemplo, é uma propriedade anexada porque é definida em elementos filho de um DockPanel, DockPanel.Dock não o DockPanel próprio. A DockPanel classe define um campo estático DependencyProperty , chamado DockPropertye, em seguida, fornece GetDock e SetDock métodos como acessadores públicos para a propriedade anexada.

Propriedades anexadas em XAML

Em XAML, você define propriedades anexadas usando a sintaxe <attached property provider type>.<property name>, onde o provedor de propriedade anexado é a classe que define a propriedade anexada. O exemplo a seguir mostra como um elemento filho de pode definir o valor da DockPanelDockPanel.Dock propriedade.

<DockPanel>
    <TextBox DockPanel.Dock="Top">Enter text</TextBox>
</DockPanel>

O uso é semelhante a uma propriedade estática em que você faz referência ao tipo que possui e registra a propriedade anexada (por exemplo, DockPanel), não o nome da instância.

Quando você especifica uma propriedade anexada usando um atributo XAML, somente a ação set é aplicável. Você não pode obter diretamente um valor de propriedade por meio de XAML, embora existam alguns mecanismos indiretos para comparar valores, como gatilhos em estilos.

Propriedades anexadas no WPF

As propriedades anexadas são um conceito XAML, as propriedades de dependência são um conceito WPF. No WPF, a maioria das propriedades anexadas relacionadas à interface do usuário em tipos WPF são implementadas como propriedades de dependência. As propriedades anexadas do WPF que são implementadas como propriedades de dependência oferecem suporte a conceitos de propriedade de dependência, como metadados de propriedade, incluindo valores padrão de metadados.

Modelos de uso de propriedade anexada

Embora qualquer objeto possa definir um valor de propriedade anexado, isso não significa que a definição de um valor produzirá um resultado tangível ou que o valor será usado por outro objeto. O objetivo principal das propriedades anexadas é fornecer uma maneira para objetos de uma ampla variedade de hierarquias de classe e relacionamentos lógicos relatarem informações comuns para o tipo que define a propriedade anexada. O uso da propriedade anexada normalmente segue um destes modelos:

  • O tipo que define a propriedade anexada é o pai dos elementos que definem valores para a propriedade anexada. O tipo pai itera seus objetos filho por meio de lógica interna que atua na estrutura da árvore de objetos, obtém os valores e age sobre esses valores de alguma maneira.
  • O tipo que define a propriedade anexada é usado como o elemento filho para vários elementos pai e modelos de conteúdo possíveis.
  • O tipo que define a propriedade anexada representa um serviço. Outros tipos definem valores para a propriedade anexada. A seguir, quando o elemento que define a propriedade é avaliado no contexto do serviço, os valores da propriedade anexada são obtidos por meio da lógica interna da classe de serviço.

Um exemplo de uma propriedade anexada definida pelos pais

O cenário típico em que o WPF define uma propriedade anexada é quando um elemento pai oferece suporte a uma coleção de elementos filho e o elemento pai implementa um comportamento com base nos dados relatados por cada um de seus elementos filho.

DockPanel define a DockPanel.Dock propriedade anexada. DockPanel tem código de nível de classe, especificamente MeasureOverride e ArrangeOverride, isso faz parte de sua lógica de renderização. Uma DockPanel instância verifica se algum de seus elementos filho imediatos definiu um valor para DockPanel.Dock. Em caso afirmativo, esses valores se tornam entradas para a lógica de renderização aplicada a cada elemento filho. Embora seja teoricamente possível que as propriedades anexadas influenciem elementos além do pai imediato, o comportamento definido para uma instância aninhada DockPanel é interagir apenas com sua coleção de elementos filho imediatos. Portanto, se você definir DockPanel.Dock em um elemento que não tem pai, nenhum erro ou exceção será gerado e você teria criado um valor de propriedade global que não DockPanel será consumido por nenhum DockPanel.

Propriedades anexadas no código

As propriedades anexadas no WPF não têm os métodos CLR e set wrapper típicos porque as propriedades podem ser definidas de fora do namespace CLRget. Para permitir que um processador XAML defina esses valores ao analisar XAML, a classe que define a propriedade anexada deve implementar métodos de acessador dedicados na forma de Get<property name> e Set<property name>.

Você também pode usar os métodos de acessador dedicado para obter e definir uma propriedade anexada no código, conforme mostrado no exemplo a seguir. No exemplo, myTextBox é uma instância da TextBox classe.

DockPanel myDockPanel = new();
TextBox myTextBox = new();
myTextBox.Text = "Enter text";

// Add child element to the DockPanel.
myDockPanel.Children.Add(myTextBox);

// Set the attached property value.
DockPanel.SetDock(myTextBox, Dock.Top);
Dim myDockPanel As DockPanel = New DockPanel()
Dim myTextBox As TextBox = New TextBox()
myTextBox.Text = "Enter text"

' Add child element to the DockPanel.
myDockPanel.Children.Add(myTextBox)

' Set the attached property value.
DockPanel.SetDock(myTextBox, Dock.Top)

Se você não adicionar myTextBox como um elemento filho do myDockPanel, a chamada SetDock não gerará uma exceção ou terá qualquer efeito. Somente um valor definido em um elemento filho de um DockPanel.DockDockPanel pode afetar a renderização, e a renderização será a mesma se você definir o valor antes ou depois de adicionar o elemento filho ao DockPanel.

De uma perspectiva de código, uma propriedade anexada é como um campo de suporte que tem acessadores de método em vez de acessadores de propriedade e pode ser definida em qualquer objeto sem precisar primeiro ser definida nesses objetos.

Metadados de propriedade anexados

Os metadados de uma propriedade anexada geralmente não são diferentes dos de uma propriedade de dependência. Ao registrar uma propriedade anexada, use FrameworkPropertyMetadata para especificar características da propriedade, como se a propriedade afeta a renderização ou a medição. Quando você especifica um valor padrão substituindo metadados de propriedade anexados, esse valor se torna o padrão para a propriedade anexada implícita em instâncias da classe de substituição. Se um valor de propriedade anexado não for definido de outra forma, o valor padrão será relatado quando a propriedade for consultada usando o Get<property name> acessador com uma instância da classe em que você especificou os metadados.

Para habilitar a herança de valor de propriedade em uma propriedade, use propriedades anexadas em vez de propriedades de dependência não anexadas. Para obter mais informações, consulte Herança de valor de propriedade.

Propriedades anexadas personalizadas

Quando criar uma propriedade anexada

A criação de uma propriedade anexada é útil quando:

  • Você precisa de um mecanismo de configuração de propriedade disponível para classes diferentes da classe definidora. Um cenário comum é para o layout da interface do usuário, por exemplo DockPanel.Dock, , Panel.ZIndexe Canvas.Top são todos exemplos de propriedades de layout existentes. No cenário de layout, os elementos filho de um elemento de controle de layout são capazes de expressar os requisitos de layout para seu pai de layout e definir um valor para uma propriedade anexada definida pelo pai.

  • Uma de suas classes representa um serviço, e você deseja que outras classes integrem o serviço de forma mais transparente.

  • Você deseja suporte ao Visual Studio WPF Designer, como a capacidade de editar uma propriedade por meio da janela Propriedades . Para obter mais informações, consulte Visão geral sobre a criação de controles.

  • Você deseja usar a herança do valor da propriedade.

Como criar uma propriedade anexada

Se sua classe define uma propriedade anexada exclusivamente para uso por outros tipos, sua classe não precisa derivar de DependencyObject. Caso contrário, siga o modelo WPF de ter uma propriedade anexada também como uma propriedade de dependência, derivando sua classe de DependencyObject.

Defina sua propriedade anexada como uma dependência na classe definidora declarando um public static readonly campo do tipo DependencyProperty. Em seguida, atribua o valor de retorno do RegisterAttached método ao campo, que também é conhecido como identificador de propriedade de dependência. Siga a convenção de nomenclatura de propriedade WPF que distingue os campos das propriedades que eles representam, nomeando o campo <property name>Propertyidentificador . Além disso, forneça métodos estáticos Get<property name> e Set<property name> acessadores, que permitem que o sistema de propriedades acesse sua propriedade anexada.

O exemplo a seguir mostra como registrar uma propriedade de dependência usando o RegisterAttached método e como definir os métodos de acessador. No exemplo, o nome da propriedade anexada é , portanto, o campo identificador é HasFishnomeado HasFishProperty, e os métodos de acessador são nomeados GetHasFish e SetHasFish.

public class Aquarium : UIElement
{
    // Register an attached dependency property with the specified
    // property name, property type, owner type, and property metadata.
    public static readonly DependencyProperty HasFishProperty = 
        DependencyProperty.RegisterAttached(
      "HasFish",
      typeof(bool),
      typeof(Aquarium),
      new FrameworkPropertyMetadata(defaultValue: false,
          flags: FrameworkPropertyMetadataOptions.AffectsRender)
    );

    // Declare a get accessor method.
    public static bool GetHasFish(UIElement target) =>
        (bool)target.GetValue(HasFishProperty);

    // Declare a set accessor method.
    public static void SetHasFish(UIElement target, bool value) =>
        target.SetValue(HasFishProperty, value);
}
Public Class Aquarium
    Inherits UIElement

    ' Register an attached dependency property with the specified
    ' property name, property type, owner type, and property metadata.
    Public Shared ReadOnly HasFishProperty As DependencyProperty =
        DependencyProperty.RegisterAttached("HasFish", GetType(Boolean), GetType(Aquarium),
            New FrameworkPropertyMetadata(defaultValue:=False,
                flags:=FrameworkPropertyMetadataOptions.AffectsRender))

    ' Declare a get accessor method.
    Public Shared Function GetHasFish(target As UIElement) As Boolean
        Return target.GetValue(HasFishProperty)
    End Function

    ' Declare a set accessor method.
    Public Shared Sub SetHasFish(target As UIElement, value As Boolean)
        target.SetValue(HasFishProperty, value)
    End Sub

End Class

O acessador Get

A assinatura do get método acessador é public static object Get<property name>(DependencyObject target), onde:

  • target é a partir da qual a DependencyObject propriedade anexada é lida. O target tipo pode ser mais específico que DependencyObject. Por exemplo, o método accessor digita o DockPanel.GetDocktarget como UIElement porque a propriedade anexada destina-se a ser definida em UIElement instâncias. UiElement indiretamente deriva de DependencyObject.
  • O tipo de retorno pode ser mais específico que object. Por exemplo, o método digita o valor retornado como Dock porque o GetDock valor de retorno deve ser uma Dock enumeração.

Observação

O get acessador de uma propriedade anexada é necessário para suporte à vinculação de dados em ferramentas de design, como Visual Studio ou Blend para Visual Studio.

O acessador Set

A assinatura do set método acessador é public static void Set<property name>(DependencyObject target, object value), onde:

  • target é a propriedade na qual a DependencyObject propriedade anexada é escrita. O target tipo pode ser mais específico que DependencyObject. Por exemplo, o método digita o SetDocktarget as UIElement porque a propriedade anexada destina-se a ser definida em UIElement instâncias. UiElement indiretamente deriva de DependencyObject.
  • O value tipo pode ser mais específico que object. Por exemplo, o SetDock método requer um Dock valor. O carregador XAML precisa ser capaz de gerar o tipo a partir da cadeia de caracteres de marcação que representa o value valor da propriedade anexada. Portanto, deve haver conversão de tipo, serializador de valor ou suporte de extensão de marcação para o tipo que você usa.

Atributos de propriedade anexados

O WPF define vários atributos .NET que fornecem informações sobre propriedades anexadas a processos de reflexão e também a consumidores de informações de reflexão e propriedade, como designers. Os designers usam atributos .NET definidos pelo WPF para limitar as propriedades mostradas na janela de propriedades, para evitar sobrecarregar os usuários com uma lista global de todas as propriedades anexadas. Você pode considerar a aplicação desses atributos às suas próprias propriedades anexadas personalizadas. A finalidade e a sintaxe dos atributos do .NET são descritas nestas páginas de referência:

Saiba mais

  • Para obter mais informações sobre como criar uma propriedade anexada, consulte Registrar uma propriedade anexada.
  • Para obter cenários de uso mais avançados para propriedades de dependência e propriedades anexadas, consulte Propriedades de dependência personalizadas.
  • Você pode registrar uma propriedade como uma propriedade anexada e uma propriedade de dependência, e incluir wrappers de propriedade convencionais. Dessa forma, uma propriedade pode ser definida em um elemento usando wrappers de propriedade e também em qualquer outro elemento usando a sintaxe de propriedade anexada XAML. Para obter um exemplo, consulte FrameworkElement.FlowDirection.

Confira também