Partilhar via


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

Uma propriedade anexada é um conceito XAML (Extensible Application Markup Language). As propriedades anexadas permitem que pares extras de propriedade/valor sejam definidos em qualquer elemento XAML que derive de DependencyObject, mesmo que o elemento não defina essas propriedades extras em seu modelo de objeto. 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 envoltório de propriedade convencional.

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

Por que usar propriedades anexadas

Uma propriedade anexada permite que um elemento filho especifique um valor exclusivo para uma propriedade que está definida em um elemento pai. Um cenário comum é um elemento filho que especifica como ele deve ser renderizado na interface do usuário por seu elemento pai. Por exemplo, DockPanel.Dock é uma propriedade anexada porque é definida em elementos filho de um DockPanel, mas não no DockPanel em si. A classe DockPanel define um campo DependencyProperty estático, chamado DockPropertye, em seguida, fornece métodos GetDock e SetDock 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 DockPanel pode definir o valor da propriedade DockPanel.Dock.

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

O uso é semelhante a uma propriedade estática na medida 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 definida é aplicável. Não se pode obter diretamente um valor de propriedade através do XAML, embora existam alguns mecanismos indiretos para comparar valores, como os gatilhos de 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 anexados

Embora qualquer objeto possa definir um valor de propriedade anexado, isso não significa que definir um valor produzirá um resultado tangível ou o valor será usado por outro objeto. O principal objetivo das propriedades anexadas é fornecer uma maneira para objetos de uma ampla variedade de hierarquias de classe e relações lógicas 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 através da 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 possíveis elementos pai e modelos de conteúdo.
  • O tipo que define a propriedade anexada representa um serviço. Outros tipos definem valores para a propriedade anexada. Em seguida, quando o elemento que define a propriedade é avaliado no contexto do serviço, os valores de propriedade anexados são obtidos por meio da lógica interna da classe de serviço.

Um exemplo de uma propriedade anexada definida pelo pai

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 em dados relatados por cada um de seus elementos filho.

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

Propriedades anexadas no código

As propriedades anexadas no WPF não têm os métodos típicos de encapsulamento get e set do CLR porque as propriedades podem ser definidas fora do espaço de nomes do CLR. 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 classe TextBox.

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 tu não adicionares myTextBox como um elemento filho do myDockPanel, chamar SetDock não irá gerar uma exceção nem terá qualquer efeito. Somente um valor DockPanel.Dock definido em um elemento filho de um DockPanel 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 perspetiva 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 primeiro precisar ser definida nesses objetos.

Metadados de propriedade anexados

Os metadados de uma propriedade anexada geralmente não são diferentes 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 anexada, 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 acessador de Get<property name> com uma instância da classe onde você especificou os metadados.

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

Propriedades anexadas personalizadas

Quando criar uma propriedade anexada

Criar 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 exemplos de propriedades de layout existentes. No cenário de layout, os elementos filho de um elemento controlador de layout são capazes de expressar os requisitos de layout ao seu elemento pai de layout e definir um valor para uma propriedade associada definida pelo pai.

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

  • Você deseja suporte do Visual Studio WPF Designer, como a capacidade de editar uma propriedade por meio da janela Propriedades. Para mais informações, consulte a visão geral de autoria do Control.

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

Como criar uma propriedade anexada

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

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

O exemplo a seguir mostra como registrar uma propriedade de dependência usando o método RegisterAttached e como definir os métodos de acessador. No exemplo, o nome da propriedade anexada é HasFish, portanto, o campo identificador é nomeado 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 acessor 'get'

A assinatura do método de acesso get é public static object Get<property name>(DependencyObject target), em que:

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

Observação

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

O acessador Definir

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

  • target é o DependencyObject onde a propriedade anexada está definida. O tipo target pode ser mais específico do que DependencyObject. Por exemplo, o método SetDock tipifica o target como UIElement uma vez que a propriedade anexada se destina a ser definida nas instâncias de UIElement. UiElement deriva indiretamente de DependencyObject.
  • O tipo value pode ser mais específico do que object. Por exemplo, o método SetDock requer um valor Dock. O carregador XAML precisa ser capaz de gerar o tipo value a partir da string de marcação que representa o valor da propriedade associada. Portanto, deve haver conversão de tipo, serializador de valor ou suporte para extensões de marcação para o tipo que você usa.

Atributos de propriedade anexados

A WPF define vários atributos .NET que fornecem informações sobre propriedades anexadas a processos de reflexão e também a consumidores dessas informações, como projetistas. 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 aplicar esses atributos às suas próprias propriedades anexadas personalizadas. A finalidade e a sintaxe dos atributos .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 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. Desta forma, uma propriedade pode ser configurada num elemento usando wrappers de propriedades e também em qualquer outro elemento usando a sintaxe de propriedade associada do XAML. Para obter um exemplo, consulte FrameworkElement.FlowDirection.

Ver também