Compartilhar via


Precedência de valores de propriedade de dependência

Este tópico explica como o funcionamento do sistema de propriedades do Windows Presentation Foundation (WPF) pode afetar o valor de uma propriedade de dependência e descreve a precedência pela qual aspectos do sistema de propriedades se aplicadam ao valor efetivo de uma propriedade.

Este tópico contém as seguintes seções.

  • Pré-requisitos
  • O sistema de propriedades do WPF
  • Propriedades de dependência podem ser "definidas" em vários locais
  • Lista de precedência na definição de propriedades de dependência
  • TemplatedParent
  • A propriedade Style
  • Estilos padrão (temas).
  • Referências e associações dinâmicas a recursos
  • Coerção, animações e valor base
  • Comportamento de disparadores
  • Precedência de ClearValue e valores
  • Tópicos relacionados

Pré-requisitos

Este tópico assume que você entende propriedades de dependência da perspectiva de um consumidor de propriedades de dependência existentes nas classes do WPF , e já leu Visão geral sobre propriedades de dependência. Para que você siga os exemplos deste tópico, você também deve entender Extensible Application Markup Language (XAML) e saber como escrever aplicações WPF.

O sistema de propriedades do WPF

O sistema a propriedade do WPF WPF oferece uma maneira poderosa para que o valor das propriedades de dependência seja determinado por uma variedade de fatores, permitindo recursos como validação de propriedade em tempo real, associação postergada e notificação de propriedades relacionadas quando ocorre alterações em valores de outras propriedades. A ordem exata e a lógica que são usadas para determinar os valores de propriedades de dependência são razoavelmente complexas. Conhecer esta ordem irá ajudá-lo a evitar definições desnecessárias de propriedades, e pode também clarificar confusões sobre exatamente porque alguma tentativa de prever ou influenciar o valor de uma propriedade de dependência não acabou resultando no valor esperado.

Propriedades de dependência podem ser "definidas" em vários locais

A seguir temos um exemplo de XAML onde a mesma propriedade (Background) tem três diferentes operações de "definição" que podem influenciar seu valor.

    <Button Background="Red">
      <Button.Style>
        <Style TargetType="{x:Type Button}">
          <Setter Property="Background" Value="Green"/>
          <Style.Triggers>
            <Trigger Property="IsMouseOver" Value="True">
              <Setter Property="Background" Value="Blue" />
            </Trigger>
          </Style.Triggers>
        </Style>
      </Button.Style>
Click
    </Button>

Aqui, que cor você espera que seja aplicada — vermelho, verde ou azul?

Com exceção de valores animados e coerção, definições locais de propriedade são definidas com precedência mais alta. Se você definir um valor localmente, você pode esperar que o valor seja aceito, até mesmo acima de quaisquer estilos ou modelos de controle. No exemplo, o Background é definido localmente como vermelho. Portanto, o estilo definido neste escopo, mesmo sendo um estilo implícito que de outro modo seria aplicado a todos os elementos desse tipo nesse escopo, não tem a precedência mais alta para dar à propriedade Background seu valor. Se você removesse o valor vermelho local da instância do botão, então, o estilo teria precedência e o botão obteria o valor de plano de fundo do estilo. No estilo, os disparadores têm precedência, portanto o botão será azul se o mouse estiver sobre ele, e verde caso contrário.

Lista de precedência na definição de propriedades de dependência

A ordem a seguir é a ordem definitiva que o sistema de propriedades usa para atribuir os valores das propriedades de dependência em tempo de execução. As precedências mais altas são listadas primeiro. Esta lista se expande em algumas das generalizações feitas no Visão geral sobre propriedades de dependência.

  1. Coerção do sistema de propriedades Para obter detalhes sobre coerção, consulte Coerção, animação e valor base posteriormente neste tópico.

  2. Animações ativas, ou animações com comportamento em espera. Para poder ter qualquer efeito prático, uma animação de uma propriedade deve ser capaz de ter precedência sobre o valor base (não animado), mesmo se esse valor foi definido localmente. Para obter detalhes, consulte Coerção, animação e valor base posteriormente neste tópico.

  3. Valor local. Um valor local pode ser definido por meio da conveniência da propriedade envolvente (wrapper), que também equivale à definição como um atributo ou elemento de propriedade em XAML, ou por uma chamada à SetValue na API, usando uma propriedade de uma instância específica. Se você definir um valor local usando associação ou um recurso, cada um esses atua na precedência como se um valor direto fosse definido.

  4. Propriedades de modelo TemplatedParent. Um elemento tem um TemplatedParent se ele foi criado como parte de um modelo (um ControlTemplate ou um DataTemplate). Para obter detalhes sobre quando isso se aplica, consulte TemplatedParent posteriormente neste tópico. Dentro do modelo, a precedência a seguir se aplica:

    1. Disparadores do modelo TemplatedParent.

    2. Definições de propriedades (geralmente através de atributos XAML) no modelo TemplatedParent.

  5. Estilo implícito. Só se aplica a propriedade Style. A propriedade Style é preenchida por qualquer recurso de estilo com uma chave que corresponda ao tipo de elemento. Esse recurso de estilo deve existir na página ou no aplicativo; a pesquisa por um recurso de estilo implícito não prossegue nos temas.

  6. Disparadores de estilos. Os disparadores em estilos de página ou de aplicativo (esses estilos podem ser estilos explícitos ou implícitos, mas não os estilos padrão, os quais têm prioridade mais baixa).

  7. Disparadores de modelo. Qualquer disparador de um modelo em um estilo, ou de um modelo aplicado diretamente.

  8. Estilo de Setters. Valores de um Setter em estilos de página ou de aplicativo.

  9. O estilo padrão (tema). Para obter detalhes sobre quando isso se aplica, e como estilos de tema se relacionam com os modelos dentro de estilos de tema, consulte Estilos padrão (tema) posteriormente neste tópico. Em um estilo padrão, a ordem de precedência a seguir se aplica:

    1. Disparadores ativos no estilo de tema.

    2. Setters no estilo de tema.

  10. Herança Algumas propriedades de dependência herdam seus valores de elemento pai para elementos filho, de forma que eles não precisam ser definidos especificamente em cada elemento em um aplicativo. Para mais detalhes, consulte Herança de Valor de Propriedade

  11. Valor padrão de metadados de propriedades de dependência. Qualquer propriedade de dependência pode ter um valor padrão conforme estabelecido pelo sistema de registro de propriedades daquela determinada propriedade. Além disso, classes derivadas que herdam uma propriedade de dependência têm a opção de sobrescrever esses metadados (inclusive o valor padrão) por tipo. Consulte Metadados de Propriedade de Dependência para obter mais informações. Como a herança é verificada antes do valor padrão, para uma propriedade herdada, o valor padrão de um elemento pai tem precedência sobre o de um elemento filho. Consequentemente, se uma propriedade herdável não é definida em qualquer lugar, o valor padrão conforme especificado na raiz ou no pai será usado em vez do valor padrão no elemento filho.

TemplatedParent

TemplatedParent não se aplica como um item precedência a qualquer propriedade de um elemento que você declarar diretamente em linguagem padrão de marcação de aplicativos. O conceito de TemplatedParent existe somente para itens filho em uma árvore visual que passa a existir através da aplicação de um modelo. Quando o sistema de propriedades procura o modelo TemplatedParent para um valor, ele está procurando pelo modelo que criou esse elemento. Os valores de propriedade do modelo TemplatedParent geralmente agem como se eles tivessem sido definidos como um valor local no elemento filho, mas essa menor precedência em relação ao valor local existe pois modelos são potencialmente compartilhados. Para obter detalhes, consulte:TemplatedParent.

A propriedade Style

A ordem de pesquisa descrita anteriormente se aplica todas as propriedades de dependência possíveis, exceto um: the Style propriedade. A propriedade Style é exclusiva em que não pode ser ela própria estilizada, portanto, os itens de precedência de 5 a 8 não se aplicam. Além disso, animação ou coerção de Style não são recomendadas (e animar um Style exigiria uma classe de animação personalizada). Isso deixa três maneiras em que a propriedade Style pode ser definida:

  • Estilo explícito. A propriedade Style é definida diretamente. Na maioria das situações o estilo não é definido de forma embutida, mas, em vez disso, é referenciado como um recurso, por chave explícita. Nesse caso, a própria propriedade Style atua como se fosse um valor local, item 3 de precedência.

  • Estilo implícito. A propriedade Style não é definida diretamente. No entanto, o Style existe em algum nível na sequência de consulta por recursos (página, aplicativo) e é associado a uma chave de recurso que corresponde ao tipo ao qual o estilo for ser aplicado. Nesse caso, a Style propriedade próprio age, uma precedência identificada na sequência sistema autônomo item 5. Essa condição pode ser detectada por meio de DependencyPropertyHelper em relação a Style propriedade e procurando ImplicitStyleReference nos resultados.

  • O estilo padrão, também conhecido como estilo tema. A propriedade Style não é definida diretamente e na verdade é lida como null até chegar em tempo de execução. Nesse caso, o estilo vem da avaliação em tempo de execução do tema que faz parte do mecanismo de apresentação do WPF.

Para estilos implícitos não em temas, o tipo deve coincidir exatamente — uma classe MyButton derivada de Button não vai implicitamente usar um estilo para Button.

Estilos padrão (temas).

Cada controle que acompanha o WPF tem um estilo padrão. Esse estilo padrão potencialmente varia por tema, o que faz com que este estilo padrão seja algumas vezes conhecido como um estilo de tema.

A informação mais importantes encontrada em um estilo padrão para um controle é seu modelo de controle, que existe no estilo de tema como um Setter para sua propriedade Template. Se não houvesse nenhum modelo vindo dos estilos padrão, um controle sem um modelo personalizado como parte de um estilo personalizado não teria nenhuma aparência. O modelo do estilo padrão fornece uma estrutura básica à aparência visual de cada controle e também define as conexões entre as propriedades definidas na árvore visual do modelo e a classe de controle correspondente. Cada controle expõe um conjunto de propriedades que podem influenciar a aparência visual do controle sem substituir totalmente o modelo. Por exemplo, considere a aparência visual padrão de um controle Thumb, que é um componente de um ScrollBar.

Um Thumb possui certas propriedades personalizáveis. O modelo padrão de um Thumb cria uma árvore visual/estrutura básica com vários componentes Border aninhados para criar uma aparência de alto relevo. Se uma propriedade que é parte do modelo se destina a ser exposta para personalização pela classe Thumb, então essa propriedade deve ser exposta por um TemplateBinding dentro do modelo. No caso de Thumb, várias propriedades dessas bordas compartilham um modelo fazendo associação a propriedades como Background ou BorderThickness. Mas determinadas outras propriedades ou disposições visuais são definidas embutidas no modelo de controle ou são associadas a valores provenientes diretamente do tema; e não podem ser alteradas a não ser que se substitua o modelo inteiro. Geralmente, se uma propriedade vem de um pai "templated" e não é exposta por uma associação de modelo, ela não pode ser ajustada por estilos pois não há uma maneira fácil de definí-la como alvo. Mas essa propriedade pode ainda ser influenciada por herança de valor de propriedade no modelo aplicado, ou pelo valor padrão.

Os estilos de tema usam um tipo como chave em suas definições. No entanto, quando os temas são aplicados a uma determinada instância de um elemento, a consulta de temas para esse tipo é executada verificando-se a propriedade DefaultStyleKey em um controle. Isso é para contraste usando tipo literal, sistema autônomo estilos implícitos. O valor de DefaultStyleKey herdaria às classes derivadas de classes mesmo que o implementador não alterado (a maneira de alterar a propriedade pretendida é não para substituí-lo no nível de propriedade, mas para, em vez disso, alteração de metadados da propriedade valor padrão). Essa indireção permite que classes base definam os tema de estilos para elementos derivado que não tenham um estilo (ou, mais importante, não tenham um modelo dentro desse estilo e assim não têm nenhuma aparência visual padrão). Assim, você pode fazer MyButton derivar de Button e ainda receber o modelo padrão de Button. Se você fosse o autor do controle MyButton e você quisesse um comportamento diferente, você poderia sobrescrever os metadados da propriedade de dependência de DefaultStyleKey em MyButton para retornar uma chave diferente e, em seguida, definir os estilos de tema relevantes, inclusive o modelo para MyButton que você deve empacotar com o controle MyButton. Para obter mais detalhes sobre temas, estilos e criação de controles, consulte Visão geral sobre criação de controles.

Referências e associações dinâmicas a recursos

Referências dinâmicas a recursos e operações de associação são ambas tratadas como se estivessem definindo o valor ao qual estão sendo aplicadas. Por exemplo, um recurso dinâmico aplicado a um valor local funciona como item 3 de precedência, uma associação a uma propriedade Setter em um estilo de tema se aplica como um item 9 de precedência; e assim por diante. Como tanto referências dinâmicas a recursos quanto asociações devem ser capazes de obter valores do estado do aplicativo em tempo de execução, isso implica que o processo de determinar a precedência de valor de propriedades para uma dada propriedade se estende ao tempo de execução também.

Referências dinâmicas a recursos não são, estritamente falando, parte do sistema de propriedades, mas têm uma ordem de consulta específica que interage com a sequência listada acima. Essa precedência está documentada mais detalhadamente em Visão geral sobre Recursos. É a soma dessa precedência básica: elemento de página raiz, o aplicativo, o tema, o sistema.

Não somente recursos dinâmicos e associações operam na mesma precedência que um valor local, eles são realmente um valor local, mas com um valor que é adiado. Uma consequência disso é que se você tiver um recurso dinâmico ou uma associação em vigor para um valor de propriedade, qualquer valor local que você venha a definir subsequentemente substitui totalmente a associação. Mesmo se você chamar ClearValue para limpar o valor definido localmente, o recurso dinâmico ou a associação não serão restaurados. Na verdade, se você chamar ClearValue em uma propriedade que tem um recurso dinâmico ou associação em vigor (sem nenhum valor local "literal"), eles serão limpos pela chamada ClearValue também.

Coerção, animações e valor base

Tanto coerção quanto animação agem em um valor que é chamado de "valor base" em todo este SDK. O valor base é, portanto, qualquer valor determinado através da avaliação dos itens até que o item 2 é alcançado.

Para uma animação, o valor base pode ter um efeito sobre o valor animado se essa animação não especificar o "From" e o "To" para certos comportamentos, ou se a animação deliberadamente reverte de volta ao valor base quando concluída. Para verificar isso na prática, execute o De, Para e By exemplo de vParalores de destino de ParanimParação. Tente configurar os valores locais da altura do retângulo no exemplo, de modo que o valor local inicial fique diferente de qualquer "From" na animação. Você notará que as animações se iniciam imediatamente usando os valores de "From" e substituem o valor base depois de iniciadas. A animação pode especificar o retorno para o valor encontrado antes da animação depois que ela é concluída, especificando o comportamento de parada FillBehavior. Posteriormente, a precedência normal é usada para a determinação do valor base.

Várias animações podem ser aplicadas a uma única propriedade, com cada uma dessas animações possivelmente tendo sido definida a partir de diferentes pontos na precedência de valor. No entanto, esses animações potencialmente irão compor seus valores, em vez de apenas aplicar a animação de precedência mais alta. Isso depende de como exatamente as animações são definidas e do tipo do valor que está sendo animado. Para mais informações sobre animar propriedades, consulte Revisão de Animação.

Coerção se aplica no nível mais alto de todos. Até mesmo uma animação já em execução está sujeita a coerção de valor. Certas propriedades de dependência existentes no WPF tem coerção interna. Para uma propriedade de dependência personalizada, você define o comportamento de coerção ao escrever um CoerceValueCallback e passar a callback como parte dos metadados ao criar a propriedade. Você também pode sobrescrever o comportamento de coerção de propriedades existentes, substituindo os metadados dessas propriedades em um classe derivada. Coerção interage com o valor base de tal forma que as restrições em coerção são aplicadas como essas restrições se encontram no momento, mas o valor base ainda é mantido. Portanto, se as restrições de coerção são posteriores levantadas, a coerção irá retornar o valor mais próximo possível do valor base; e potencialmente a influência da coerção em uma propriedade acabará assim que todas as restrições sejam levantadas. Para obter mais informações sobre o comportamento de coerção, consulte Validação e Callbacks de Propriedade de Dependência.

Comportamento de disparadores

Controles geralmente definem o comportamento de disparadores como parte do seu estilo padrão em temas. A definição de propriedades locais nos controles pode impedir que os disparadores possam responder visualmente ou comportamentalmente a eventos causados pelo usuário. O uso mais comum de um disparador de propriedade é para propriedades de controle ou estado como IsSelected. Por exemplo, por padrão quando um Button é desabilitado (o disparador para IsEnabled fica false), o valor Foreground no estilo de tema é o que faz com que o controle pareça "cinza". Mas se você tiver definido um valor local para Foreground, a cor cinza normal será ignorada pela precedência da sua definição local da propriedade, mesmo nesse cenário com disparador de propriedade. Seja cuidadoso ao definir valores para propriedades que possuem comportamentos de disparador no nível de tema, e certifique-se de que você não está interferindo impropriamente com o experiência do usuário pretendida para o controle.

Precedência de ClearValue e valores

O método ClearValue fornece que uma maneira rápida para limpar qualquer valor aplicado localmente a uma propriedade de dependência definida em um elemento. No entanto, chamar ClearValue não garante que o valor padrão (conforme estabelecido nos metadados durante o registro da propriedade) será o novo valor efetivo. Todos os outros participantes na precedência de valor ainda estão ativos. Somente o valor definido localmente foi removido da sequência de precedência. Por exemplo, se você chamar ClearValue em uma propriedade onde essa propriedade também seja definida por um estilo de tema, em seguida, o valor do tema será aplicado como o novo valor em vez do padrão definido nos metadados. Você pode ver isto ilustrado em Restaurando o exemplo de valores padrão, embora nesse caso o estilo aplicado seja um estilo implícito definido em recursos no nível do aplicativo. Se você deseja retirar todos valores de propriedade do processo e definir o valor como sendo o padrão nos metadados registrado, você pode obter esse valor definitivamente consultando os metadados da propriedade de dependência, e, em seguida, usando o valor padrão para definir localmente a propriedade com uma chamada a SetValue.

Consulte também

Conceitos

Visão geral sobre propriedades de dependência

Propriedades de Dependência Personalizada

Validação e Callbacks de Propriedade de Dependência

Referência

DependencyObject

DependencyProperty