Compartilhar 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 de propriedade/valor extras sejam definidos em qualquer elemento XAML derivado de , 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 normalmente são definidas como uma forma especializada de propriedade de dependência que não tem um wrapper 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, é ú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, DockPanel.Dock é uma propriedade anexada porque é definida em elementos filho de um DockPanel, não no DockPanel próprio. A DockPanel classe define um campo estático DependencyProperty , chamado DockProperty, e fornece GetDock métodos 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>, em que 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 DockPanel.Dock propriedade.

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

O uso é semelhante a uma propriedade estática, pois 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 haja 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 do 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 dão 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 configuração de um valor produzirá um resultado tangível ou que o valor será usado por outro objeto. A principal finalidade das propriedades anexadas é fornecer uma maneira para que objetos de uma ampla variedade de hierarquias de classe e relações lógicas relatem 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 atua nesses 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 pelo pai

O cenário típico em que o WPF define uma propriedade anexada é quando um elemento pai dá 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, que faz parte de sua lógica de renderização. Uma DockPanel instância verifica se algum de seus elementos filhos imediatos definiu um valor para DockPanel.Dock. Nesse caso, 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 um elemento que não tenha pai DockPanel , nenhum erro ou exceção será gerado e você terá 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 CLR get e set wrapper típicos porque as propriedades podem ser definidas de fora do namespace 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 dedicados 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 de myDockPanel, a chamada SetDock não gerará uma exceção nem terá qualquer efeito. Somente um DockPanel.Dock valor definido em um elemento filho de a 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 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 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 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 de definição. 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 de controle de layout são capazes de expressar requisitos de layout para seu layout pai 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 da criação de controle.

  • Você deseja usar a herança de valor de propriedade.

Como criar uma propriedade anexada

Se sua classe definir uma propriedade anexada exclusivamente para uso por outros tipos, sua classe não precisará derivar de DependencyObject. Caso contrário, siga o modelo do WPF de fazer com que uma propriedade anexada também seja uma propriedade de dependência, derivando sua classe de DependencyObject.

Defina sua propriedade anexada como uma dependência na classe de definição declarando um public static readonly campo do tipo DependencyProperty. Em seguida, atribua o valor retornado 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 do 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, o que permite 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 do acessador. No exemplo, o nome da propriedade anexada é HasFish, portanto, o campo identificador é nomeado HasFishProperty, e os métodos acessadores 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 é o DependencyObject a partir do qual a propriedade anexada é lida. O target tipo pode ser mais específico que DependencyObject. Por exemplo, o DockPanel.GetDock método acessador digita o target como UIElement porque a propriedade anexada deve 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 GetDock o valor retornado como Dock porque o valor retornado deve ser uma Dock enumeração.

Observação

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

O acessador Set

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

  • target é o DependencyObject no qual a propriedade anexada é gravada. O target tipo pode ser mais específico que DependencyObject. Por exemplo, o SetDock método digita o target como UIElement porque a propriedade anexada deve 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 value tipo da cadeia de caracteres de marcação que representa o valor da propriedade anexada. Portanto, deve haver conversão de tipo, serializador de valor ou suporte a extensão de marcação para o tipo que você usa.

Atributos de propriedade anexados

O WPF define vários atributos do .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 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