Prioridad de los valores de propiedades de dependencia

En este tema se explica cómo puede afectar el trabajo del sistema de propiedades de Windows Presentation Foundation (WPF) al valor de una propiedad de dependencia y se describe la precedencia de aplicación de los aspectos del sistema de propiedades al valor efectivo de una propiedad.

Requisitos previos

En este tema, se supone que entiende las propiedades de dependencia desde la perspectiva de un consumidor de propiedades de dependencia existentes en las clases WPF y que ha leído Información general sobre las propiedades de dependencia. Para seguir los ejemplos de este tema, también debe comprender el lenguaje Lenguaje XAML (Extensible Application Markup Language) y saber cómo escribir aplicaciones de WPF.

Sistema de propiedades de WPF

El sistema de propiedades de WPF permite que el valor de las propiedades de dependencia se determine de forma eficaz mediante una serie de factores, que habilita características como la validación de propiedades en tiempo real, el enlace en tiempo de ejecución y la notificación de propiedades relacionadas de cambios a valores de otras propiedades. El orden y la lógica exactos que se usan para determinar los valores de las propiedades de dependencia son bastante complejos. Conocer este orden le evitará establecer propiedades innecesarias y puede eliminar la confusión sobre el motivo por el que un intento de influir en el valor de una propiedad de dependencia o de anticiparlo no dio como resultado el valor esperado.

Las propiedades de dependencia podrían ser "set" en varios lugares

A continuación se incluye un ejemplo XAML en el que la misma propiedad ( Background ) tiene tres operaciones "SET" diferentes que podrían influir en el 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>

¿Qué color espera que se aplique aquí: rojo, verde o azul?

A excepción de los valores animados y la coerción, los conjuntos de propiedades locales se establecen con la precedencia más alta. Si establece un valor localmente, puede esperar que este se respete, incluso por encima de cualquier estilo o plantilla de control. Aquí en el ejemplo, Background está establecido en rojo de forma local. Por lo tanto, el estilo definido en este ámbito, aunque sea un estilo implícito que, de otro modo, se aplicaría a todos los elementos de ese tipo en ese ámbito, no es la prioridad más alta para dar Background su valor a la propiedad. En el caso de quitar el valor local de Red desde esa instancia de Button, el estilo tendría precedencia y el botón obtendría el valor de Background del estilo. Dentro del estilo, los desencadenadores tienen precedencia, por lo que el botón será azul si el mouse está encima de él y verde en caso contrario.

Lista de precedencia de configuración de propiedades de dependencia

El siguiente es el orden definitivo que usa el sistema de propiedades al asignar los valores de tiempo de ejecución de las propiedades de dependencia. La precedencia más alta aparece primero. Esta lista desarrolla algunas de las generalizaciones realizadas en la Información general sobre las propiedades de dependencia.

  1. Coerción del sistema de propiedades. Para obtener más información sobre la coerción, consulte Coerción, animación y valor base más adelante en este tema.

  2. Animaciones activas o animaciones con un comportamiento Hold. Para tener cualquier efecto práctico, una animación de una propiedad debe poder tener precedencia sobre el valor base (inanimado), aunque dicho valor se estableciera localmente. Para obtener más información, consulte Coerción, animación y valor base más adelante en este tema.

  3. Valor local. Un valor local se puede establecer a través de la comodidad de la propiedad "wrapper", que también equivale a establecerse como un atributo o elemento de propiedad en XAML , o mediante una llamada a la SetValue API mediante una propiedad de una instancia específica. Si establece un valor local mediante un enlace o un recurso, cada uno de estos actuará con la precedencia como si se hubiese establecido un valor directo.

  4. Propiedades de la plantilla TemplatedParent. Un elemento tiene un TemplatedParent si se creó como parte de una plantilla ( ControlTemplate o DataTemplate ). Para obtener más información sobre cuándo se aplica el caso anterior, consulte TemplatedParent más adelante en este tema. En la plantilla, se aplica la siguiente precedencia:

    1. Desencadenadores de la TemplatedParent plantilla.

    2. Conjuntos de propiedades (normalmente a través XAML de atributos) en la TemplatedParent plantilla.

  5. Estilo implícito. Solo se aplica a la propiedad Style. La propiedad Style se rellena con cualquier recurso de estilo que tenga una clave que coincida con el tipo de ese elemento. Ese recurso de estilo debe existir en la página o la aplicación; la búsqueda de un recurso de estilo implícito no continúa en los temas.

  6. Desencadenadores de estilo. Desencadenadores dentro de los estilos de una página o aplicación (estos estilos pueden ser explícitos o implícitos, pero no pueden ser predeterminados, con una precedencia más baja).

  7. Desencadenadores de plantilla. Cualquier desencadenador de una plantilla dentro de un estilo o una plantilla aplicada directamente.

  8. Establecedores de estilo. Valores de dentro de los Setter estilos de la página o la aplicación.

  9. Estilo (tema) predeterminado. Para obtener más información sobre cuándo se aplica y cómo se relacionan los estilos de tema con las plantillas dentro de los estilos de tema, consulte Estilos (temas) predeterminados más adelante en este tema. Dentro de un estilo predeterminado, se aplica el orden de precedencia siguiente:

    1. Desencadenadores activos del estilo de tema.

    2. Establecedores del estilo de tema.

  10. Ella. Algunas propiedades de dependencia heredan sus valores del elemento primario a los elementos secundarios, de manera que no se tienen que establecer específicamente en cada elemento de una aplicación. Para obtener información detallada, consulte Herencia de valores de propiedad.

  11. Valor predeterminado de los metadatos de las propiedades de dependencia. Cualquier propiedad de dependencia puede tener un valor predeterminado establecido en el registro del sistema de propiedades de esa propiedad concreta. Además, las clases derivadas que heredan una propiedad de dependencia tienen la opción de invalidar esos metadatos (incluido el valor predeterminado) por tipo. Para obtener más información, consulte Metadados de las propiedades de dependencia. Puesto que la herencia se comprueba antes que el valor predeterminado, para una propiedad heredada, un valor predeterminado de un elemento primario tiene precedencia sobre un elemento secundario. Por consiguiente, si una propiedad heredable no está establecida en ningún lugar, se usa el valor predeterminado tal como se especifica en la raíz o el elemento primario, en lugar del valor predeterminado del elemento secundario.

TemplatedParent

TemplatedParent, como un elemento de precedencia, no se aplica a ninguna propiedad de un elemento que se declara directamente en la marcación de aplicación estándar. El concepto de TemplatedParent existe solo para los elementos secundarios dentro de un árbol visual que se genera a través de la aplicación de la plantilla. Cuando el sistema de propiedades busca TemplatedParent un valor en la plantilla, está buscando en la plantilla que creó ese elemento. Los valores de propiedad de la TemplatedParent plantilla suelen actuar como si se hubieran establecido como un valor local en el elemento secundario, pero esta menor prioridad con respecto al valor local existe porque las plantillas están potencialmente compartidas. Para obtener información detallada, vea TemplatedParent.

Propiedad Style

El orden de búsqueda descrito anteriormente se aplica a todas las propiedades de dependencia posibles excepto una: la Style propiedad. La Style propiedad es única en que no se puede aplicar estilo a sí misma, por lo que no se aplican los elementos de prioridad 5 a 8. Además, Style no se recomienda la animación o la conversión (y Style la animación requeriría una clase de animación personalizada). Esto deja tres maneras de Style establecer la propiedad:

  • Estilo explícito. La Style propiedad se establece directamente. En la mayoría de los escenarios, el estilo no se define en línea, sino que se hace referencia a este como un recurso, por la clave explícita. En este caso, la propia propiedad Style actúa como si fuera un valor local, el elemento de precedencia 3.

  • Estilo implícito. La Style propiedad no se establece directamente. Sin embargo, el Style existe en algún nivel en la secuencia de búsqueda de recursos (página, aplicación) y se codifica mediante una clave de recurso que coincide con el tipo al que se va a aplicar el estilo. En este caso, la Style propiedad en sí actúa con una prioridad identificada en la secuencia como elemento 5. Esta condición se puede detectar mediante DependencyPropertyHelper el uso Style de en la propiedad y la búsqueda ImplicitStyleReference en los resultados.

  • Estilo predeterminado, también conocido como estilo del tema. La Style propiedad no se establece directamente y, de hecho, se leerá null hasta el tiempo de ejecución. En este caso, el estilo procede de la evaluación del tema en tiempo de ejecución que forma parte del motor de presentación de WPF.

En el caso de los estilos implícitos que no están en los temas, el tipo debe coincidir exactamente con la MyButton Button clase derivada de. no utilizará implícitamente un estilo para Button .

Estilos (temas) predeterminados

Todos los controles que se suministran con WPF tienen un estilo predeterminado. Ese estilo predeterminado puede variar según el tema, motivo por el cual se denomina a veces "estilo de tema".

La información más importante que se encuentra dentro de un estilo predeterminado para un control es su plantilla de control, que existe en el estilo de tema como un establecedor para su Template propiedad. Si no hubiera ninguna plantilla en los estilos predeterminados, un control sin una plantilla personalizada como parte de un estilo personalizado no tendría ninguna apariencia visual. La plantilla del estilo predeterminado proporciona a la apariencia visual de cada control una estructura básica, además de definir las conexiones entre las propiedades definidas en el árbol visual de la plantilla y la clase de control correspondiente. Cada control expone un conjunto de propiedades que puede influir en la apariencia visual del control sin reemplazar completamente la plantilla. Por ejemplo, considere la apariencia visual predeterminada de un Thumb control, que es un componente de ScrollBar .

Un Thumb tiene ciertas propiedades personalizables. La plantilla predeterminada de un Thumb crea un árbol visual o de estructura básica con varios componentes anidados Border para crear una apariencia biselada. Si una propiedad que forma parte de la plantilla está pensada para que la clase se exponga para la personalización Thumb , esa propiedad debe estar expuesta por un TemplateBindingen la plantilla. En el caso de Thumb , varias propiedades de estos bordes comparten un enlace de plantilla a propiedades como Background o BorderThickness . No obstante, otras propiedades u organizaciones visuales están codificadas de forma rígida en la plantilla de control o enlazadas a valores que proceden directamente del tema, y no se pueden cambiar a poco de reemplazar la plantilla completa. Por lo general, si una propiedad procede de un elemento primario con plantilla y no se expone mediante un enlace a plantilla, no puede ajustarse mediante estilos porque no hay ninguna forma sencilla de establecerla como destino. No obstante, aún se podría influir en esa propiedad mediante la herencia de valores de propiedad de la plantilla aplicada o el valor predeterminado.

Los estilos de tema usan un tipo como clave en sus definiciones. Sin embargo, cuando los temas se aplican a una instancia de elemento determinada, la búsqueda de temas para este tipo se realiza mediante la comprobación de la DefaultStyleKey propiedad en un control. Esto es lo contrario a usar el literal Type, como hacen los estilos implícitos. El valor de se DefaultStyleKey heredaría de las clases derivadas aunque el implementador no lo cambiara (la forma prevista de cambiar la propiedad no es invalidarla en el nivel de propiedad, sino que en su lugar cambie su valor predeterminado en los metadatos de la propiedad). Este direccionamiento indirecto permite que las clases base definan los estilos de tema de elementos derivados que, de lo contrario, no tendrían ningún estilo (o más importante aún, no tendrían ninguna plantilla dentro de ese estilo y no tendrían, por tanto, ninguna apariencia visual predeterminada en absoluto). Por lo tanto, puede derivar MyButton de Button y seguirá teniendo la Button plantilla predeterminada. Si fuera el autor del control de MyButton y deseaba un comportamiento diferente, podría invalidar los metadatos de la propiedad de dependencia de DefaultStyleKey en MyButton para devolver una clave distinta y, a continuación, definir los estilos de tema relevantes, incluida la plantilla para MyButton que debe empaquetar con el MyButton control. Para obtener más detalles sobre los temas, los estilos y la creación de controles, consulte Información general sobre la creación de controles.

Enlace y referencias de recursos dinámicos

Las operaciones de enlace y referencias de recursos dinámicos respetan la precedencia de la ubicación en la que están establecidas. Por ejemplo, un recurso dinámico aplicado a un valor local actúa por elemento de precedencia 3, un enlace para un establecedor de propiedad dentro de un estilo de tema se aplica al elemento de precedencia 9 y así sucesivamente. Dado que el enlace y las referencias de recursos dinámicos deben ser capaces de obtener los valores del estado de tiempo de ejecución de la aplicación, esto implica que el proceso real de determinar la precedencia de los valores de propiedad para cualquier propiedad determinada se extiende también al tiempo de ejecución.

Las referencias de recursos dinámicos no forman parte del sistema de propiedades en sentido estricto, pero tienen un orden de búsqueda propio que interactúa con la secuencia citada anteriormente. Esa precedencia se documenta con más detalle en Recursos XAML. El resumen básico de esa precedencia es: elemento a raíz de la página, aplicación, tema y sistema.

Los enlaces y los recursos dinámicos tienen la precedencia de donde se establecieron, pero el valor se aplaza. Una consecuencia de esto es que, si establece un recurso dinámico o un enlace en un valor local, cualquier cambio en el valor local reemplazará el recurso dinámico o el enlace completamente. Incluso si llama al ClearValue método para borrar el valor establecido localmente, no se restaurará el recurso dinámico o el enlace. De hecho, si llama a ClearValue en una propiedad que tiene un recurso dinámico o un enlace en contexto (sin ningún valor local literal), se borran también con la ClearValue llamada.

SetCurrentValue

El SetCurrentValue método es otra manera de establecer una propiedad, pero no se encuentra en orden de prioridad. En su lugar, SetCurrentValue permite cambiar el valor de una propiedad sin sobrescribir el origen de un valor anterior. Puede usar siempre SetCurrentValue que desee establecer un valor sin asignar a ese valor la prioridad de un valor local. Por ejemplo, si una propiedad se establece mediante un desencadenador y luego se le asigna otro valor a través de SetCurrentValue , el sistema de propiedades seguirá respetando el desencadenador y la propiedad cambiará si se produce la acción del desencadenador. SetCurrentValue permite cambiar el valor de la propiedad sin darle un origen con una prioridad más alta. Del mismo modo, puede usar SetCurrentValue para cambiar el valor de una propiedad sin sobrescribir un enlace.

Coerción, animaciones y valor base

Tanto la coerción como la animación actúan sobre un valor que se denomina el "valor base" en este SDK. El valor base es, por tanto, cualquier valor que se determine mediante la evaluación ascendente de los elementos hasta alcanzar el elemento 2.

Para una animación, el valor base puede tener un efecto en el valor animado si la animación no especifica los valores "From" y "To" para ciertos comportamientos o si se revierte deliberadamente al valor base al completarse. Para verlo en la práctica, ejecute el Ejemplo de valores de destino de animación From, To y By. Intente establecer los valores locales del alto del rectángulo del ejemplo, de modo que el valor local inicial difiera de cualquier valor "From" de la animación. Observará que las animaciones se inician inmediatamente mediante los valores "From" y reemplazan el valor base una vez iniciadas. La animación podría especificar que se devuelva al valor encontrado antes de la animación una vez completada especificando la detención FillBehavior . Después, se usa la precedencia normal para la determinación del valor base.

Varias animaciones podrían aplicarse a una propiedad única y cada una de estas animaciones se podría haber definido desde diferentes puntos de la precedencia de valores. Sin embargo, estas animaciones compondrán potencialmente sus valores, en lugar de aplicar la animación de mayor precedencia simplemente. Esto depende de la exactitud con la que estén definidas las animaciones y del tipo de valor que se esté animando. Para más información sobre la animación de propiedades, vea Información general sobre animaciones.

La coerción se aplica en el nivel más alto de todos. Incluso una animación que ya se está ejecutando está sujeta a la coerción de valores. Ciertas propiedades de dependencia existentes en WPF tienen la coerción integrada. En el caso de una propiedad de dependencia personalizada, defina el comportamiento de la coerción para una propiedad de dependencia personalizada escribiendo CoerceValueCallback y pasando la devolución de llamada como parte de los metadatos al crear la propiedad. También puede invalidar el comportamiento de la coerción de las propiedades existentes mediante la invalidación de los metadatos de esa propiedad en una clase derivada. La coerción interactúa con el valor base de forma que se aplican las restricciones en la coerción, ya que esas restricciones existen en el momento, pero el valor base se sigue conservando. Por lo tanto, si las restricciones en la coerción se levantan posteriormente, la coerción devolverá el valor más próximo posible a ese valor base y la influencia de la coerción sobre una propiedad cesará potencialmente en cuanto se levanten todas las restricciones. Para obtener más información sobre el comportamiento de la coerción, consulte Devoluciones de llamada y validación de las propiedades de dependencia.

Comportamientos de los desencadenadores

Los controles suelen definir los comportamientos de los desencadenadores como parte de su estilo predeterminado en los temas. Establecer las propiedades locales en los controles puede impedir que los desencadenadores sean capaces de responder a eventos controlados por el usuario, ya sea de manera visual o conductual. El uso más común de un desencadenador de propiedad es para las propiedades de control o de estado como IsSelected . Por ejemplo, de forma predeterminada, cuando un Button está deshabilitado (el desencadenador de IsEnabled es false ), el Foreground valor del estilo de tema es el que hace que el control aparezca "atenuado". Sin embargo, si ha establecido un Foreground valor local, el color gris normal se sobrescribirá en la prioridad del conjunto de propiedades local, incluso en este escenario desencadenado por la propiedad. Tenga precaución al establecer valores de propiedades con comportamientos de desencadenador de nivel de tema y asegúrese de no interferir excesivamente en la experiencia de usuario prevista para este control.

Precedencia de los valores y ClearValue

El ClearValue método proporciona un medio conveniente para borrar cualquier valor aplicado localmente de una propiedad de dependencia que se establece en un elemento. Sin embargo, llamar a ClearValue no es una garantía de que el valor predeterminado tal y como se establece en los metadatos durante el registro de la propiedad es el nuevo valor efectivo. Todos los demás participantes en la precedencia de valores siguen estando activos. Solo el valor establecido localmente se quitó de la secuencia de precedencia. Por ejemplo, si llama a ClearValue en una propiedad en la que la propiedad también se establece mediante un estilo de tema, el valor del tema se aplica como el nuevo valor en lugar del valor predeterminado basado en metadatos. Si desea sacar todos los participantes del valor de propiedad del proceso y establecer el valor en el valor predeterminado de los metadatos registrados, puede obtener ese valor predeterminado de manera definitiva consultando los metadatos de la propiedad de dependencia y, a continuación, puede usar el valor predeterminado para establecer localmente la propiedad con una llamada a SetValue .

Consulte también