Visão geral das propriedades anexadas

Uma propriedade anexada é um conceito definido por XAML. Uma propriedade anexada destina-se a ser usada como um tipo de propriedade global que é configurável em qualquer objeto de dependência. No Windows Presentation Foundation (WPF), as propriedades anexadas são normalmente definidas como uma forma especializada de propriedade de dependência que não tem a propriedade convencional "wrapper".

Pré-requisitos

Este artigo pressupõe que você entenda as propriedades de dependência da perspectiva de um consumidor de propriedades de dependência existentes em classes do Windows Presentation Foundation (WPF) e tenha lido a Visão geral das propriedades de dependência. Para seguir os exemplos neste artigo, você também deve entender XAML e saber como escrever aplicativos WPF.

Por que usar propriedades anexadas

Uma finalidade de uma propriedade anexada é permitir que diferentes elementos filho especifiquem valores exclusivos para uma propriedade definida em um elemento pai. Uma aplicação específica desse cenário é fazer com que os elementos filho informem o elemento pai de como eles devem ser apresentados na interface do usuário (UI). Um exemplo é a DockPanel.Dock propriedade. A DockPanel.Dock propriedade é criada como uma propriedade anexada porque foi projetada para ser definida em elementos contidos em um DockPanel e não em DockPanel si mesmo. A DockPanel classe define o campo estático DependencyProperty chamado DockPropertye, em seguida, fornece os GetDock métodos e SetDock como acessadores públicos para a propriedade anexada.

Propriedades anexadas em XAML

Em XAML, as propriedades anexadas são definidas por meio do uso da sintaxe AttachedPropertyProvider.PropertyName

Veja a seguir um exemplo de como você pode definir DockPanel.Dock em XAML:

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

O uso é um pouco semelhante a uma propriedade estática; Você sempre faz referência ao tipo DockPanel que possui e registra a propriedade anexada, em vez de se referir a qualquer instância especificada pelo nome.

Além disso, como uma propriedade anexada em XAML é um atributo definido na marcação, somente a operação de conjuntos tem alguma relevância. Não é possível obter uma propriedade diretamente em XAML, apesar de existirem alguns mecanismos indiretos para comparar valores, como gatilhos em estilos (para mais detalhes, consulte Estilo e modelagem).

Implementação de propriedades anexadas no WPF

No Windows Presentation Foundation (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 são um conceito XAML, enquanto as propriedades de dependência são um conceito WPF. Como as propriedades anexadas do WPF são propriedades de dependência, elas oferecem suporte a conceitos de propriedade de dependência, como metadados de propriedade e valores padrão desses metadados de propriedade.

Como as propriedades anexadas são usadas pelo tipo proprietário

Embora as propriedades anexadas possam ser definidas em qualquer objeto, isso não significa, automaticamente, que a definição da propriedade produzirá um resultado tangível ou que o valor será usado por outro objeto. Em geral, as propriedades anexadas são criadas para que os objetos provenientes de uma grande variedade de hierarquias de classe possíveis ou relações lógicas possam reportar informações comuns para o tipo que define a propriedade anexada. O tipo que define a propriedade anexada normalmente segue um destes modelos:

  • O tipo que define a propriedade anexada é concebido para que possa ser o elemento pai dos elementos que definirão valores para a propriedade anexada. Em seguida, o tipo itera os objetos filho por meio de lógica interna com relação a algumas estruturas de árvore de objeto, obtém os valores e age sobre eles de alguma maneira.

  • O tipo que define a propriedade anexada será usado como 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 propriedade anexada definida pelo pai

O cenário mais típico em que o WPF define uma propriedade anexada é quando um elemento pai dá suporte a uma coleção de elementos filho e também implementa um comportamento em que as especificidades do comportamento são relatadas individualmente para cada elemento filho.

DockPaneldefine a propriedade anexada e tem código DockPanel.Dock de nível de classe como parte de sua lógica de renderização (especificamente, MeasureOverride e DockPanelArrangeOverride). Uma DockPanel instância sempre verificará se algum de seus elementos filho imediatos definiu um valor para DockPanel.Dock. Nesse caso, tais valores se tornam uma entrada para a lógica de renderização aplicada ao elemento filho em questão. Cada instância aninhada DockPanel trata suas próprias coleções de elementos filho imediatos, mas esse comportamento é específico da implementação para como DockPanel os valores de processos DockPanel.Dock . Teoricamente, é possível ter propriedades anexadas que influenciam elementos além do pai imediato. Se a propriedade anexada DockPanel.Dock for definida em um elemento que não tenha nenhum elemento pai para agir sobre ele, nenhum DockPanel erro ou exceção será gerado. Isso simplesmente significa que um valor de propriedade global foi definido, mas não tem nenhum pai atual DockPanel que possa consumir as informações.

Propriedades anexadas no código

As propriedades anexadas no WPF não têm os métodos típicos de "wrapper" do CLR para fácil acesso/configuração. Isso ocorre porque a propriedade anexada não é necessariamente parte do namespace CLR para instâncias em que a propriedade é definida. No entanto, um processador XAML deve ser capaz de definir esses valores quando o XAML for analisado. Para oferecer suporte a um uso efetivo da propriedade anexada, o tipo de proprietário da propriedade anexada deve implementar métodos de acessador dedicados no formato Get PropertyName e SetPropertyName. Esses métodos de acesso dedicados também são úteis para obter ou definir a propriedade anexada em código. De uma perspectiva de código, uma propriedade anexada é semelhante a um campo de suporte que tem métodos de acesso em vez de acessadores de propriedade; além disso, o campo de suporte pode existir em qualquer objeto, sem precisar ser definido especificamente.

O exemplo a seguir mostra como você pode definir uma propriedade anexada em código. Neste exemplo, myCheckBox é uma instância da CheckBox classe.

DockPanel myDockPanel = new DockPanel();
CheckBox myCheckBox = new CheckBox();
myCheckBox.Content = "Hello";
myDockPanel.Children.Add(myCheckBox);
DockPanel.SetDock(myCheckBox, Dock.Top);
Dim myDockPanel As New DockPanel()
Dim myCheckBox As New CheckBox()
myCheckBox.Content = "Hello"
myDockPanel.Children.Add(myCheckBox)
DockPanel.SetDock(myCheckBox, Dock.Top)

Semelhante ao caso XAML, se myCheckBox ainda não tivesse sido adicionado como um elemento filho da quarta linha de código, a quinta linha de código não geraria uma exceção, mas o valor da myDockPanel propriedade não interagiria com um DockPanel pai e, portanto, não faria nada. Somente um valor definido em um elemento filho combinado com a presença de um elemento pai causará um DockPanel.DockDockPanel comportamento efetivo no aplicativo renderizado. (Nesse caso, você pode definir a propriedade anexada e, em seguida, anexar à árvore. Ou você pode anexar à árvore e, em seguida, definir a propriedade anexada. Qualquer ordem de ação fornece o mesmo resultado.)

Metadados da propriedade anexada

Ao registrar a propriedade, é definido para especificar características da propriedade, FrameworkPropertyMetadata como se a propriedade afeta a renderização, a medição e assim por diante. Em geral, os metadados de uma propriedade anexada não diferem dos metadados de uma propriedade de dependência. Se você especificar um valor padrão em uma substituição para metadados da propriedade anexada, esse valor vai se tornar o valor padrão da propriedade anexada implícita em instâncias da classe de substituição. Especificamente, o valor padrão será relatado se algum processo consultar o valor de uma propriedade anexada por meio do acessador do método Get para essa propriedade, especificando uma instância da classe em que os metadados foram especificados, e caso o valor dessa propriedade anexada não tenha sido definido de outra maneira.

Se você desejar habilitar a herança de valor da propriedade em uma propriedade, deverá usar propriedades anexadas em vez de propriedades de dependência não anexadas. Para obter detalhes, consulte Herança do valor da propriedade.

Propriedades anexadas personalizadas

Quando criar uma propriedade anexada

É possível criar uma propriedade anexada quando há um motivo para ter um mecanismo de configuração de propriedade disponível para classes diferentes da classe de definição. O cenário mais comum para isso é o layout. Exemplos de propriedades de layout existentes são DockPanel.Dock, Panel.ZIndexe Canvas.Top. O cenário habilitado aqui é que os elementos que existem como elementos filho para elementos de controle do layout conseguem expressar os requisitos de layout para os elementos pai de layout individualmente, sendo que cada um configura um valor da propriedade que o pai definiu como propriedade anexada.

Outro cenário para usar uma propriedade anexada é quando a classe representa um serviço, e você deseja que classes possam integrar o serviço de forma mais transparente.

Outro cenário é receber suporte ao Visual Studio WPF Designer, como a edição da janela Propriedades . Para obter mais informações, consulte Visão geral da criação de controle.

Como mencionado anteriormente, será necessário registrar como propriedade anexada se você quiser usar a herança de valor da propriedade.

Como criar uma propriedade anexada

Se sua classe estiver definindo a propriedade anexada estritamente para uso em outros tipos, a classe não precisará derivar de DependencyObject. Mas você precisa derivar de se você seguir o modelo WPF geral de DependencyObject ter sua propriedade anexada também ser uma propriedade de dependência.

Defina sua propriedade anexada como uma propriedade de dependência declarando um public static readonly campo do tipo DependencyProperty. Você define esse campo usando o valor de retorno do RegisterAttached método. O nome do campo deve corresponder ao nome da propriedade anexada, anexado com a cadeia de caracteres Property, para seguir o padrão WPF estabelecido de nomear os campos de identificação versus as propriedades que eles representam. O provedor de propriedade anexado também deve fornecer os métodos estáticos Get PropertyName e SetPropertyName como acessadores para a propriedade anexada, e se isso não for possível usar a propriedade anexada pelo sistema de propriedades.

Observação

Se você omitir o acessador get da propriedade anexada, a vinculação de dados na propriedade não funcionará em ferramentas de design, como o Visual Studio e o Blend para Visual Studio.

O acessador get

A assinatura para o acessador GetPropertyName deve ser:

public static object GetPropertyName(object target)

  • O objeto target pode ser especificado como um tipo mais específico na sua implementação. Por exemplo, o método digita o DockPanel.GetDock parâmetro como UIElement, porque a propriedade anexada destina-se apenas a ser definida em UIElement instâncias.

  • O valor retornado pode ser especificado como um tipo mais específico na sua implementação. Por exemplo, o método digita-o como Dock, porque o GetDock valor só pode ser definido para essa enumeração.

O acessador set

A assinatura para o acessador SetPropertyName deve ser:

public static void SetPropertyName(object target, object value)

  • O objeto target pode ser especificado como um tipo mais específico na sua implementação. Por exemplo, o método digita-o SetDock como UIElement, porque a propriedade anexada destina-se apenas a ser definida em UIElement instâncias.

  • O objeto value pode ser especificado como um tipo mais específico na sua implementação. Por exemplo, o método digita-o como Dock, porque o SetDock valor só pode ser definido para essa enumeração. Lembre-se de que o valor para esse método é a entrada proveniente do carregador de XAML, quando ele encontra a propriedade anexada em um uso da propriedade anexada na marcação. Essa entrada é o valor especificado como um valor de atributo XAML na marcação. Portanto, deve haver conversão de tipo, serializador de valores ou suporte à extensão de marcação para o tipo que usar, de modo que o tipo adequado possa ser criado por meio do valor do atributo (que é, basicamente, apenas uma cadeia de caracteres).

O exemplo a seguir mostra o registro de propriedade de dependência (usando o RegisterAttached método), bem como os acessadores GetPropertyName e SetPropertyName. No exemplo, o nome da propriedade anexada é IsBubbleSource. Portanto, os acessadores devem ser nomeados como GetIsBubbleSource e SetIsBubbleSource.

public static readonly DependencyProperty IsBubbleSourceProperty = DependencyProperty.RegisterAttached(
  "IsBubbleSource",
  typeof(Boolean),
  typeof(AquariumObject),
  new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsRender)
);
public static void SetIsBubbleSource(UIElement element, Boolean value)
{
  element.SetValue(IsBubbleSourceProperty, value);
}
public static Boolean GetIsBubbleSource(UIElement element)
{
  return (Boolean)element.GetValue(IsBubbleSourceProperty);
}
Public Shared ReadOnly IsBubbleSourceProperty As DependencyProperty = DependencyProperty.RegisterAttached("IsBubbleSource", GetType(Boolean), GetType(AquariumObject), New FrameworkPropertyMetadata(False, FrameworkPropertyMetadataOptions.AffectsRender))
Public Shared Sub SetIsBubbleSource(ByVal element As UIElement, ByVal value As Boolean)
    element.SetValue(IsBubbleSourceProperty, value)
End Sub
Public Shared Function GetIsBubbleSource(ByVal element As UIElement) As Boolean
    Return CType(element.GetValue(IsBubbleSourceProperty), Boolean)
End Function

Atributos de propriedade anexada

O WPF define vários atributos .NET que se destinam a fornecer informações sobre propriedades anexadas a processos de reflexão e a usuários típicos de informações de reflexão e propriedade, como designers. Como as propriedades anexadas têm um tipo de escopo ilimitado, os designers precisam de uma maneira de evitar sobrecarregar os usuários com uma lista global de todas as propriedades anexadas que são definidas em uma implementação de tecnologia específica que usa XAML. Os atributos .NET que o WPF define para propriedades anexadas podem ser usados para definir o escopo das situações em que uma determinada propriedade anexada deve ser mostrada em uma janela de propriedades. Você também pode considerar a possibilidade de aplicar esses atributos para suas próprias propriedades anexadas personalizadas. A finalidade e a sintaxe dos atributos .NET são descritas nas páginas de referência apropriadas:

Aprendendo mais sobre propriedades anexadas

  • Para obter mais informações sobre como criar uma propriedade anexada, consulte Registrar uma propriedade anexada.

  • Para ver mais cenários de uso avançados para as propriedades de dependência e as propriedades anexadas, consulte Propriedades de dependência personalizada.

  • Também é possível registrar uma propriedade como propriedade anexada e como propriedade de dependência, mas ainda expor implementações de “wrapper”. Nesse caso, a propriedade pode ser definida nesse elemento ou em qualquer elemento por meio da sintaxe de propriedade anexada XAML. Um exemplo de uma propriedade com um cenário apropriado para usos padrão e anexados é FrameworkElement.FlowDirection.

Confira também