Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
El funcionamiento del sistema de propiedades de Windows Presentation Foundation (WPF) afecta al valor de una propiedad de dependencia. En este artículo se explica cómo la precedencia de diferentes entradas basadas en propiedades dentro del sistema de propiedades de WPF determina el valor efectivo de una propiedad de dependencia.
Prerrequisitos
El artículo asume que tiene un conocimiento básico de las propiedades de dependencia y que ha leído Descripción general de las propiedades de dependencia. Para seguir los ejemplos de este artículo, le ayuda si está familiarizado con el lenguaje de marcado extensible de aplicaciones (XAML) y sabe cómo escribir aplicaciones WPF.
El sistema de propiedades de WPF
El sistema de propiedades de WPF usa una variedad de factores para determinar el valor de las propiedades de dependencia, como la validación de propiedades en tiempo real, la vinculación tardía y las notificaciones de cambio de propiedad para las propiedades relacionadas. Aunque el orden y la lógica que se usan para determinar los valores de propiedades de dependencia son complejos, aprenderlos te ayudará a evitar configuraciones de propiedades innecesarias y a averiguar por qué un intento de establecer una propiedad de dependencia no resultó en el valor esperado.
Propiedades de dependencia configuradas en múltiples lugares
En el ejemplo XAML siguiente se muestra cómo tres operaciones "establecer" diferentes en la propiedad del Background botón pueden influir en su valor.
<StackPanel>
<StackPanel.Resources>
<ControlTemplate x:Key="ButtonTemplate" TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
</ControlTemplate>
</StackPanel.Resources>
<Button Template="{StaticResource ButtonTemplate}" Background="Red">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="Blue"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Yellow" />
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
Which color do you expect?
</Button>
</StackPanel>
En el ejemplo, la propiedad Background
se establece localmente en Red
. Sin embargo, el estilo implícito declarado en el ámbito del botón intenta establecer la propiedad Background
en Blue
. Y, cuando el ratón está sobre el botón, el desencadenador en el estilo implícito intenta establecer la propiedad Background
en Yellow
. Excepto la coerción y la animación, un valor de propiedad establecido localmente tiene la prioridad más alta, así que el botón será rojo, incluso con el ratón. Pero, si quita el valor establecido localmente del botón, obtendrá del estilo su valor Background
. Dentro de un estilo, los desencadenadores tienen prioridad, por lo que el botón será amarillo cuando el cursor esté sobre él y azul en caso contrario. En el ejemplo se reemplaza el valor predeterminado ControlTemplate del botón porque la plantilla predeterminada tiene un valor de ratón Background
codificado de forma rígida.
Lista de precedencia de propiedades de dependencia
La siguiente lista es el orden definitivo de precedencia que usa el sistema de propiedades al asignar valores en tiempo de ejecución a las propiedades de dependencia. La prioridad más alta se muestra primero.
Coerción del sistema de propiedades. Para obtener más información sobre la coerción, vea Coerción y animaciones.
Animaciones activas o animaciones con un comportamiento de retención. Para tener un efecto práctico, un valor de animación debe tener prioridad sobre el valor base (sin animar), incluso si el valor base se estableció localmente. Para obtener más información, vea Coerción y animaciones.
Valores locales. Puedes establecer un valor local a través de una propiedad "wrapper", que equivale a establecer un atributo o elemento de propiedad en XAML, o mediante una llamada a la SetValue API mediante una propiedad de una instancia específica. Un valor local establecido a través de un enlace o recurso tendrá la misma prioridad que un valor que se establece directamente.
Valores de las propiedades de plantilla de TemplatedParent. Un elemento tiene un TemplatedParent si se creó mediante una plantilla (ControlTemplate o DataTemplate). Para obtener más información, vea TemplatedParent. Dentro de la plantilla especificada por
TemplatedParent
, el orden de prioridad es:Desencadenantes.
Conjuntos de propiedades, normalmente a través de atributos XAML.
Estilos implícitos. Solo se aplica a la propiedad Style. El
Style
valor es cualquier recurso de estilo con un TargetType valor que coincida con el tipo de elemento. El recurso de estilo debe existir dentro de la página o la aplicación. La búsqueda de un recurso de estilo implícito no se extiende a los recursos de estilos de Temas.Desencadenadores de estilo. Un desencadenador de estilo es un desencadenador dentro de un estilo explícito o implícito. El estilo debe existir dentro de la página o aplicación. Los desencadenadores de estilos predeterminados tienen una prioridad menor.
Desencadenadores de plantilla. Un desencadenador de plantilla es un desencadenador de una plantilla aplicada directamente o de una plantilla dentro de un estilo. El estilo debe existir dentro de la página o aplicación.
Valores de establecedor de estilo. Un valor de establecedor de estilo es un valor aplicado por un Setter elemento dentro de un estilo. El estilo debe existir dentro de la página o aplicación.
Estilos predeterminados, también conocidos como estilos de tema. Para obtener más información, vea Estilos predeterminados (tema). Dentro de un estilo predeterminado, el orden de prioridad es:
Desencadenadores activos.
Setters.
Herencia. Algunas propiedades de dependencia de un elemento secundario heredan su valor del elemento primario. Por lo tanto, es posible que no sea necesario establecer valores de propiedad en todos los elementos de toda la aplicación. Para obtener más información, vea Herencia de valores de propiedad.
Valor predeterminado de los metadatos de la propiedad de dependencia Una propiedad de dependencia puede tener un valor predeterminado establecido durante el registro del sistema de propiedades de esa propiedad. Las clases derivadas que heredan una propiedad de dependencia pueden invalidar los metadatos de la propiedad de dependencia (incluido el valor predeterminado) por tipo. Para obtener más información, consulte Metadatos de propiedad de dependencia. Para una propiedad heredada, el valor predeterminado de un elemento primario tiene prioridad sobre el valor predeterminado de un elemento secundario. Por lo tanto, si no se establece una propiedad heredable, se usa el valor predeterminado de la raíz o el elemento primario en lugar del valor predeterminado del elemento secundario.
TemplatedParent
TemplatedParent la precedencia no se aplica a las propiedades de los elementos que se declaran directamente en el marcado de aplicación estándar. El TemplatedParent
concepto solo existe para los elementos secundarios dentro de un árbol visual que entran en existencia a través de la aplicación de una plantilla. Cuando el sistema de propiedades busca la plantilla especificada por TemplatedParent
para los valores de propiedad de un elemento, está buscando la plantilla que creó el elemento. Los valores de propiedad de la TemplatedParent
plantilla suelen actuar como si fueran valores establecidos localmente en el elemento, pero con menor prioridad que los valores locales reales porque las plantillas se comparten potencialmente. Para obtener más información, consulte TemplatedParent.
La propiedad Style
El mismo orden de precedencia se aplica a todas las propiedades de dependencia, excepto a la Style propiedad . La Style
propiedad es única en que no se puede aplicar estilo a sí misma. No se recomienda la coercción ni la animación de la Style
propiedad (y la animación de la Style
propiedad requeriría una clase de animación personalizada). Como resultado, no se aplican todos los elementos de precedencia. Solo hay tres maneras de establecer la Style
propiedad:
Estilo explícito. La
Style
propiedad de un elemento se establece directamente. ElStyle
valor de propiedad actúa como si fuera un valor local y tiene la misma prioridad que el elemento 3 de la lista de precedencia. En la mayoría de los escenarios, los estilos explícitos no se definen en línea y, en su lugar, se hace referencia explícitamente como un recurso, por ejemploStyle="{StaticResource myResourceKey}"
.Estilo implícito. La
Style
propiedad de un elemento no se establece directamente. En su lugar, se aplica un estilo cuando existe en algún nivel dentro de la página o aplicación, y tiene una clave de recurso que coincide con el tipo de elemento al que se aplica el estilo, por ejemplo<Style TargetType="x:Type Button">
. El tipo debe coincidir exactamente, por ejemplo<Style TargetType="x:Type Button">
, no se aplicará alMyButton
tipo aunqueMyButton
se derive deButton
. ElStyle
valor de la propiedad tiene la misma prioridad que el elemento 5 de la lista de precedencia. Se puede detectar un valor de estilo implícito llamando al método DependencyPropertyHelper.GetValueSource, pasando la propiedadStyle
y comprobando los resultados para verImplicitStyleReference
.Estilo predeterminado, también conocido como estilo de tema. La
Style
propiedad de un elemento no se establece directamente. En su lugar, procede de la evaluación de temas en tiempo de ejecución por parte del motor de presentación del WPF. Antes del tiempo de ejecución, el valor de laStyle
propiedad esnull
. ElStyle
valor de propiedad tiene la misma prioridad que el elemento 9 de la lista de precedencia.
Estilos predeterminados (tema)
Cada control que se distribuye con WPF tiene un estilo predeterminado que puede variar según el tema, por lo que a veces se conoce como estilo de tema predeterminado.
ControlTemplate es un elemento importante dentro del estilo predeterminado de un control.
ControlTemplate
es un valor definidor para la propiedad Template del estilo. Si los estilos predeterminados no contenían una plantilla, un control sin una plantilla personalizada como parte de un estilo personalizado no tendría ninguna apariencia visual. No solo define la apariencia visual de un control, sino que también define las conexiones entre las propiedades del árbol visual de la plantilla y la clase de control correspondiente. Cada control expone un conjunto de propiedades que pueden influir en la apariencia visual del control sin reemplazar la plantilla. Por ejemplo, considere la apariencia visual predeterminada de un Thumb control, que es un ScrollBar componente.
Un Thumb control tiene ciertas propiedades personalizables. La plantilla predeterminada de un control Thumb
crea una estructura básica, o árbol visual, con varios Border componentes anidados para lograr un aspecto biselado. Dentro de la plantilla, las propiedades diseñadas para ser personalizables por la Thumb
clase se exponen a través de TemplateBinding.
Los estilos predeterminados especifican en TargetType sus definiciones. La evaluación del tema en tiempo de ejecución coincide con el TargetType
de un estilo predeterminado con la DefaultStyleKey propiedad de un control. En cambio, el comportamiento de búsqueda de estilos implícitos usa el tipo real del control. El valor de DefaultStyleKey
lo heredan las clases derivadas, por lo que los elementos derivados que podrían no tener ningún estilo asociado obtengan una apariencia visual predeterminada. Por ejemplo, si deriva MyButton
de Button, MyButton
heredará la plantilla predeterminada de Button
. Las clases derivadas pueden sobrescribir el valor predeterminado de DefaultStyleKey
en los metadatos de la propiedad de dependencia. Por lo tanto, si desea una representación visual diferente para MyButton
, puede sobreescribir los metadatos de la propiedad de dependencia para DefaultStyleKey
en MyButton
, y a continuación, definir el estilo predeterminado pertinente, incluida una plantilla, que empaquetará con el control MyButton
. Para obtener más información, consulte Información general sobre la creación de controles.
Recurso dinámico
Las referencias de recursos dinámicos no forman parte técnicamente del sistema de propiedades y tienen su propio orden de búsqueda que interactúa con la lista de precedencia. Básicamente, la prioridad de las referencias de recursos dinámicos es: elemento a raíz de página, aplicación, tema y, después, sistema. Para obtener más información, consulta Recursos XAML.
Aunque las referencias y enlaces de recursos dinámicos tienen la prioridad de la ubicación en la que se establecen, el valor se aplaza. Una consecuencia de esto es que si establece un recurso dinámico o un enlace a un valor local, cualquier cambio en el valor local reemplaza completamente el recurso dinámico o el enlace. Incluso si llama al ClearValue método para borrar el valor establecido localmente, el recurso dinámico o el enlace no se restaurarán. De hecho, si llama a ClearValue
sobre una propiedad que tiene un recurso dinámico o un enlace (sin un valor local literal), se borrará el recurso dinámico o el enlace.
EstablecerValorActual
El SetCurrentValue método es otra manera de establecer una propiedad, pero no está en la lista de precedencia.
SetCurrentValue
permite cambiar el valor de una propiedad sin sobrescribir el origen de un valor anterior. Por ejemplo, si una propiedad es establecida por un desencadenador y luego se asigna otro valor mediante SetCurrentValue
, la siguiente acción del desencadenador volverá a cambiar la propiedad al valor original del desencadenador. Puede usar SetCurrentValue
siempre que quiera establecer un valor de propiedad sin proporcionar ese valor al nivel de precedencia de un valor local. Del mismo modo, puede usar SetCurrentValue
para cambiar el valor de una propiedad sin sobrescribir una vinculación.
Coerción y animación
La coerción y la animación actúan en un valor base. El valor base es el valor de la propiedad de dependencia con la prioridad más alta, determinado por la evaluación hacia arriba a través de la lista de precedencia hasta que se alcanza el elemento 2.
Si una animación no especifica valores de propiedad From y To para determinados comportamientos, o si la animación vuelve deliberadamente al valor base cuando se completa, el valor base puede afectar al valor animado. Para ver esto en la práctica, ejecute la aplicación de ejemplo Valores de destino . En el ejemplo, para el alto del rectángulo, pruebe a establecer los valores locales iniciales que difieren de cualquier From
valor. Las animaciones de ejemplo comienzan inmediatamente mediante el uso del From
valor en lugar del valor base. Al especificar Stop como FillBehavior, al finalizar una animación, se restablecerá un valor de propiedad a su valor base. La precedencia normal se usa para la determinación del valor base después de que finalice una animación.
Se pueden aplicar varias animaciones a una sola propiedad, con cada animación con una prioridad diferente. En lugar de aplicar la animación con la prioridad más alta, el motor de presentación de WPF podría componer los valores de animación, dependiendo de cómo se definieron las animaciones y el tipo de valores animados. Para obtener más información, consulte Información general sobre animaciones.
La coerción está al principio de la lista de precedencia. Incluso una animación en ejecución está sujeta a la coerción de valores. Algunas propiedades de dependencia existentes en WPF tienen coerción integrada. Para las propiedades de dependencia personalizadas, puede definir el comportamiento de coerción escribiendo un CoerceValueCallback que se pasa como parte de los metadatos al crear una propiedad. También puede invalidar el comportamiento de coerción de las propiedades existentes reemplazando los metadatos de esa propiedad en una clase derivada. La coerción interactúa con el valor base de tal manera que las restricciones de coerción se aplican tal como existen en el momento, pero el valor base todavía se conserva. Como resultado, si las restricciones de la coerción se levantan posteriormente, la coerción devolverá el valor más cercano posible al valor base y, posiblemente, la influencia de la coerción en una propiedad finalizará tan pronto como se levanten todas las restricciones. Para obtener más información sobre el comportamiento coercitivo, consulte Devoluciones de llamada y validación de propiedades de dependencia.
Comportamientos desencadenantes
Los controles suelen definir comportamientos de desencadenador como parte de su estilo predeterminado. Establecer propiedades locales en los controles puede entrar en conflicto con esos desencadenadores, lo que impide que los desencadenadores respondan (visual o de comportamiento) a eventos controlados por el usuario. Un uso común de un desencadenador de propiedad es controlar las propiedades de estado, como IsSelected o IsEnabled. Por ejemplo, de forma predeterminada, cuando un Button se deshabilita, un desencadenador del estilo de tema (IsEnabled
es false
) establece el valor de Foreground para que Button
aparezca atenuado. Si ha establecido un valor local de Foreground
, el valor de propiedad local de mayor precedencia sobrescribirá el valor del estilo de Foreground
, incluso cuando Button
esté deshabilitado. Al establecer valores de propiedad que anulan los comportamientos de activadores a nivel de tema para un control, tenga cuidado de no interferir indebidamente con la experiencia de usuario deseada para el control.
ClearValue
El ClearValue método borra cualquier valor aplicado localmente de una propiedad de dependencia para un elemento. Sin embargo, la llamada ClearValue
a no garantiza que el valor predeterminado establecido en los metadatos durante el registro de propiedades sea el nuevo valor efectivo. Todos los demás participantes de la lista de precedencia siguen activos y solo se quita el valor establecido localmente. Por ejemplo, si llama a ClearValue
en una propiedad que tiene un estilo de tema, el valor de estilo de tema se aplicará como el nuevo valor, en lugar del valor predeterminado basado en metadatos. Si desea establecer un valor de propiedad en el valor predeterminado de metadatos registrados, obtenga el valor de metadatos predeterminado consultando los metadatos de la propiedad de dependencia y establezca localmente el valor de propiedad con una llamada a SetValue.
Consulte también
.NET Desktop feedback