Instrucciones para el diseño de controles con estilosGuidelines for Designing Stylable Controls

En este documento se resume un conjunto de procedimientos recomendados que se deben tener en cuenta al diseñar un control con el que pretende crear estilos y plantillas con facilidad.This document summarizes a set of best practices to consider when designing a control which you intend to be easily stylable and templatable. Este conjunto de procedimientos se obtiene de una gran serie de pruebas y errores al trabajar con estilos de control de temas para el conjunto de controles WPFWPF integrado.We came to this set of best practices through a lot of trial and error while working on the theme control styles for the built-in WPFWPF control set. Se ha observado que una aplicación de estilos correcta es tanto una función de un modelo de objeto bien diseñado como del propio estilo.We learned that successful styling is as much a function of a well-designed object model as it is of the style itself. Este documento está destinado a los autores de controles, y no a los autores de estilos.The intended audience for this document is the control author, not the style author.

TerminologíaTerminology

La "aplicación de estilos y las plantillas" hacen referencia al conjunto de tecnologías que permiten a un autor de controles aplazar los aspectos visuales del control al estilo y la plantilla del control."Styling and templating" refer to the suite of technologies that enable a control author to defer the visual aspects of the control to the style and template of the control. Este conjunto de tecnologías incluye:This suite of technologies includes:

  • estilos (incluidos los configuradores de propiedad, los desencadenadores y los guiones gráficos),Styles (including property setters, triggers, and storyboards).

  • recursos,Resources.

  • plantillas de control,Control templates.

  • plantillas de datos.Data templates.

Para obtener una introducción a los estilos y plantillas, vea Aplicar estilos y plantillas.For an introduction to styling and templating, see Styling and Templating.

Antes de empezar: Introducción al ControlBefore You Start: Understanding Your Control

Antes de empezar con estas instrucciones, es importante conocer y definir el uso común de un control propio.Before you jump into these guidelines, it is important to understand and have defined the common usage of your control. La aplicación de estilos brinda un conjunto de posibilidades que suele ser difícil de controlar.Styling exposes an often unruly set of possibilities. Los controles escritos para un uso general (es decir, en muchas aplicaciones y por parte de muchos desarrolladores) se enfrentan al desafío de que la aplicación de estilo puede utilizarse para realizar cambios de gran alcance en el aspecto visual del control.Controls that are written to be used broadly (in many applications, by many developers) face the challenge that styling can be used to make far-reaching changes to the visual appearance of the control. De hecho, el control con estilo puede no asemejarse ni siquiera a las intenciones del autor del control.In fact, the styled control may not even resemble the control author's intentions. Habida cuenta de que la aplicación de estilo suele ofrecer una flexibilidad sin límites, puede basarse en la idea del uso común para ayudar a definir el ámbito de sus decisiones.Since the flexibility offered by styling is essentially boundless, you can use the idea of common usage to help you scope your decisions.

Para entender el uso común del control, es conveniente pensar en la propuesta de valor del control.To understand your control's common usage, it's good to think about the value proposition of the control. ¿Qué aporta este control a la tabla que no puede ofrecer ningún otro control?What does your control bring to the table that no other control can offer? El uso común no conlleva ningún aspecto visual concreto, sino más bien la filosofía del control y un conjunto razonable de expectativas sobre su uso.Common usage does not imply any specific visual appearance, but rather the philosophy of the control and a reasonable set of expectations about its usage. Este conocimiento permite realizar algunas suposiciones sobre el modelo de composición y los comportamientos definidos por el estilo del control en el caso habitual.This understanding allows you to make some assumptions about the composition model and the style-defined behaviors of the control in the common case. En el caso de ComboBox, por ejemplo, conocer el uso común no aporta ninguna información sobre si un determinado ComboBox tiene esquinas redondeadas, pero le proporcionará información sobre el hecho de que el ComboBox probablemente necesita una ventana emergente y cierto nivel de alternancia si está abierto.In the case of ComboBox, for example, understanding the common usage won't give you any insight about whether a particular ComboBox has rounded corners, but it will give you insight into the fact that the ComboBox probably needs a pop-up window and some way of toggling whether it is open.

Instrucciones generalesGeneral Guidelines

  • No aplicar de manera estricta los contratos de plantilla.Do not strictly enforce template contracts. El contrato de la plantilla de un control puede constar de elementos, comandos, enlaces, desencadenadores o incluso configuraciones de propiedades necesarios o previstos para que un control funcione correctamente.The template contract of a control might consist of elements, commands, bindings, triggers, or even property settings that are required or expected for a control to function properly.

    • Minimice los contratos lo máximo posible.Minimize contracts as much as possible.

    • Diseño con la expectativa de que, durante el período de diseño (es decir, al usar una herramienta de diseño), es habitual que una plantilla de control presente el estado de incompleta.Design around the expectation that during design time (that is, when using a design tool) it is common for a control template to be in an incomplete state. WPFWPF no ofrece una infraestructura con el estado de "redacción", por lo que los controles deben crearse con la expectativa de que dicho estado puede ser válido.does not offer a "composing" state infrastructure, so controls have to be built with the expectation that such a state might be valid.

    • No lance excepciones cuando no se respeta cualquier aspecto de un contrato de plantilla.Do not throw exceptions when any aspect of a template contract is not followed. En este sentido, los paneles no deben iniciar excepciones si tienen demasiados o muy pocos elementos secundarios.Along these lines, panels should not throw exceptions if they have too many or too few children.

  • Funcionalidad periférica de factor en elementos del asistente con plantillas.Factor peripheral functionality into template helper elements. Cada control debe centrarse en su funcionalidad principal y en su propuesta de valor verdadero, cuya definición debe realizarse según el uso común del control.Each control should be focused on its core functionality and true value proposition and defined by the control's common usage. Para ello, use los elementos de redacción y del asistente dentro de la plantilla, a fin de habilitar las visualizaciones y los comportamientos periféricos, es decir, aquellos comportamientos y visualizaciones que no contribuyen a la funcionalidad principal del control.To that end, use composition and helper elements within the template to enable peripheral behaviors and visualizations, that is, those behaviors and visualizations that do not contribute to the core functionality of the control. Los elementos del asistente se dividen en tres categorías:Helper elements fall into three categories:

    • Los tipos del asistente independientes son controles públicos y reutilizables o primitivos que se usan de forma "anónima" en una plantilla, lo que significa que ni el elemento del asistente ni el control con estilo tienen constancia del otro.Standalone helper types are public and reusable controls or primitives that are used "anonymously" in a template, meaning that neither the helper element nor the styled control is aware of the other. Técnicamente, cualquier elemento puede ser un tipo anónimo, pero en este contexto, el término describe los tipos que encapsulan la funcionalidad especializada para habilitar escenarios concretos.Technically, any element can be an anonymous type, but in this context the term describes those types that encapsulate specialized functionality to enable targeted scenarios.

    • Los elementos del asistente basados en tipos son nuevos tipos que encapsulan la funcionalidad especializada.Type-based helper elements are new types that encapsulate specialized functionality. Estos elementos se suelen diseñar con un intervalo de funcionalidad menor que los controles comunes o primitivos.These elements are typically designed with a narrower range of functionality than common controls or primitives. A diferencia de los elementos del asistente independientes, los elementos del asistente basados en tipos son conscientes del contexto en el que se utilizan y normalmente deben compartir los datos con el control a cuya plantilla pertenecen.Unlike standalone helper elements, type-based helper elements are aware of the context in which they are used and typically must share data with the control to whose template they belong.

    • Los elementos del asistente con nombre son controles comunes o primitivos que un control espera encontrar por su nombre dentro de su plantilla.Named helper elements are common controls or primitives that a control expects to find within its template by name. A estos elementos se les asigna un nombre conocido en la plantilla, de tal manera que se permite a un control encontrar el elemento e interactuar con él mediante programación.These elements are given a well-known name within the template, making it possible for a control to find the element and interact with it programmatically. En cualquier plantilla solo puede haber un elemento con un nombre determinado.There can only be one element with a given name in any template.

    En la tabla siguiente se muestran los elementos del asistente que hoy emplean los estilos del control, aunque no se trata de una lista exhaustiva:The following table shows helper elements employed by control styles today (this list is not exhaustive):

    ElementoElement TipoType Utilizada porUsed by
    ContentPresenter Basado en tiposType-based Button, CheckBox, RadioButton, Frame, etc. (todos los ContentControl tipos)Button, CheckBox, RadioButton, Frame, and so on (all ContentControl types)
    ItemsPresenter Basado en tiposType-based ListBox, ComboBox, Menu, etc. (todos los ItemsControl tipos)ListBox, ComboBox, Menu, and so on (all ItemsControl types)
    ToolBarOverflowPanel Con nombreNamed ToolBar
    Popup IndependienteStandalone ComboBox, ToolBar, Menu, ToolTip, etc.ComboBox, ToolBar, Menu, ToolTip, and so on
    RepeatButton Con nombreNamed Slider, ScrollBar, etc.Slider, ScrollBar, and so on
    ScrollBar Con nombreNamed ScrollViewer
    ScrollViewer IndependienteStandalone ListBox, ComboBox, Menu, Frame, etc.ListBox, ComboBox, Menu, Frame, and so on
    TabPanel IndependienteStandalone TabControl
    TextBox Con nombreNamed ComboBox
    TickBar Basado en tiposType-based Slider
  • Minimizar las configuraciones de propiedad o los enlaces especificados por el usuario necesarios en los elementos del asistente.Minimize required user-specified bindings or property settings on helper elements. Es habitual que un elemento del asistente requiera determinados enlaces o configuraciones de propiedad para poder funcionar correctamente en una plantilla de control.It is common for a helper element to require certain bindings or property settings in order to function properly within the control template. En la medida de lo posible, el elemento del asistente y el control con plantilla deben establecer esta configuración.The helper element and templated control should, as much as possible, establish these settings. Al establecer propiedades o enlaces, hay que tener precaución de no invalidar los valores establecidos por el usuario.When setting properties or establishing bindings, care should be taken to not override values set by the user. Los procedimientos recomendados específicos son los siguientes:Specific best practices are as follows:

    • Los elementos del asistente con nombre deben identificarse mediante el elemento primario, y este último debe establecer la configuración necesaria en el elemento del asistente.Named helper elements should be identified by the parent and the parent should establish any required settings on the helper element.

    • Los elementos del asistente basados en tipos deben establecer directamente en ellos mismos la configuración requerida.Type-based helper elements should establish any required settings directly on themselves. Para ello, es posible que el elemento del asistente deba consultar información del contexto en que se usa, incluido su TemplatedParent (el tipo de control de la plantilla en que se usa).Doing this may require the helper element to query for information context in which it is being used, including its TemplatedParent (the control type of the template in which it is being used). Por ejemplo, ContentPresenter enlaza automáticamente la Content propiedad de su TemplatedParent a su Content propiedad cuando se usa en un ContentControl tipo derivado.For example, ContentPresenter automatically binds the Content property of its TemplatedParent to its Content property when used in a ContentControl derived type.

    • No se pueden optimizar de esta forma los elementos del asistente independientes porque, por definición, ni el elemento del asistente ni el primario saben nada el uno del otro.Standalone helper elements cannot be optimized in this way because, by definition, neither the helper element nor the parent knows about the other.

  • Usar la propiedad Name para marcar los elementos dentro de una plantilla.Use the Name property to flag elements within a template. Un control que necesita buscar un elemento en su estilo para tener acceso a él mediante programación debe hacerlo mediante la propiedad Name y el paradigma FindName.A control that needs to find an element in its style in order to access it programmatically should do so using the Name property and the FindName paradigm. Un control no debería producir una excepción cuando no se encuentra un elemento, pero de forma silenciosa y sencilla debe deshabilitar la funcionalidad que requiere ese elemento.A control should not throw an exception when an element is not found, but silently and gracefully disable the functionality which required that element.

  • Usar procedimientos recomendados para expresar el estado del control y el comportamiento de un estilo.Use best practices for expressing control state and behavior in a style. A continuación se presenta una lista ordenada de los procedimientos recomendados para expresar los cambios de estado del control y el comportamiento de un estilo.The following is an ordered list of best practices for expressing control state changes and behavior in a style. Debe usar el primer elemento de la lista que habilita su escenario.You should use the first item on the list that enables your scenario.

    1. Enlace de propiedades.Property binding. Ejemplo: enlace entre ComboBox.IsDropDownOpen y ToggleButton.IsChecked.Example: binding between ComboBox.IsDropDownOpen and ToggleButton.IsChecked.

    2. Animaciones de propiedades o cambios de propiedades desencadenados.Triggered property changes or property animations. Ejemplo: el estado de desplazamiento de un Button.Example: the hover state of a Button.

    3. Comando.Command. Ejemplo: LineUpCommand / LineDownCommand en ScrollBar.Example: LineUpCommand / LineDownCommand in ScrollBar.

    4. Elementos del asistente independientes.Standalone helper elements. Ejemplo: TabPanel en TabControl.Example: TabPanel in TabControl.

    5. Tipos del asistente basados en tipos.Type-based helper types. Ejemplo: ContentPresenter en Button, TickBar en Slider.Example: ContentPresenter in Button, TickBar in Slider.

    6. Elementos del asistente con nombre.Named helper elements. Ejemplo: TextBox en ComboBox.Example: TextBox in ComboBox.

    7. Eventos traspasados desde los tipos del asistente con nombre.Bubbled events from named helper types. Si realiza escuchas de eventos traspasados desde un elemento de estilo, debe requerir que el elemento que genera el evento se pueda identificar de manera exclusiva.If you listen for bubbled events from a style element, you should require that the element generating the event can be uniquely identified. Ejemplo: Thumb en ToolBar.Example: Thumb in ToolBar.

    8. Comportamiento personalizado de OnRender.Custom OnRender behavior. Ejemplo: ButtonChrome en Button.Example: ButtonChrome in Button.

  • Usar desencadenadores de estilo (a diferencia de los desencadenadores de plantilla) con moderación.Use style triggers (as opposed to template triggers) sparingly. Los desencadenadores que afectan a las propiedades de elementos en la plantilla se deben declarar en la plantilla.Triggers that affect properties on elements in the template must be declared in the template. Los desencadenadores que afectan a las propiedades del control (no TargetName) se pueden declarar en el estilo, a menos que sepa que el cambio de la plantilla también destruye el desencadenador.Triggers that affect properties on the control (no TargetName) may be declared in the style unless you know that changing the template should also destroy the trigger.

  • Ser coherente con los patrones de estilo existentes.Be consistent with existing styling patterns. Muchas veces, hay varias formas de resolver un problema.Many times there are multiple ways to solve a problem. Debe conocer los patrones de aplicación de estilos de control existentes y, cuando sea posible, mantener la coherencia con ellos.Be aware of and, when possible, consistent with existing control styling patterns. Esto es especialmente importante para los controles que derivan del mismo tipo base (por ejemplo, ContentControl, ItemsControl, RangeBase, y así sucesivamente).This is especially important for controls that derive from the same base type (for example, ContentControl, ItemsControl, RangeBase, and so on).

  • Exponer propiedades para habilitar escenarios de personalización comunes sin volver a crear plantillas.Expose properties to enable common customization scenarios without retemplating. WPFWPF no admite partes acoplables/personalizables, por lo que un usuario de control solo puede usar dos métodos de personalización: configurar propiedades directamente o configurar propiedades con estilos.does not support pluggable/customizable parts, so a control user is left with only two methods of customization: setting properties directly or setting properties using styles. Habida cuenta de lo anterior, resulta conveniente exponer un número limitado de propiedades orientadas a escenarios de personalización muy comunes y de alta prioridad, ya que, de lo contrario, sería necesario volver a crear plantillas.With that in mind, it is appropriate to surface a limited number of properties targeted at very common, high-priority customization scenarios which would otherwise require the retemplating. A continuación se presentan procedimientos recomendados para saber cuándo y cómo habilitar escenarios de personalización:Here are best practices for when and how to enable customization scenarios:

    • Las personalizaciones muy comunes deben exponerse como propiedades en el control, a fin de que la plantilla pueda usarlas.Very common customizations should be exposed as properties on the control and consumed by the template.

    • Las personalizaciones menos comunes (aunque no poco habituales) deben exponerse como propiedades adjuntas que la plantilla debe usar.Less common (though not rare) customizations should be exposed as attached properties and consumed by the template.

    • Resulta aceptable que sea necesario volver a crear plantillas en el caso de las personalizaciones conocidas pero poco habituales.It is acceptable for known but rare customizations to require retemplating.

Consideraciones sobre temasTheme Considerations

  • Los estilos de temas deben tratar de tener una semántica de propiedades coherente en todos los temas, pero sin garantizarlo.Theme styles should attempt to have consistent property semantics across all themes, but make no guarantee. Como parte de su documentación, el control debe tener un documento en que se describa la semántica de la propiedad del control, es decir, el "significado" de una propiedad para un control.As part of its documentation, your control should have a document describing the control's property semantics, that is, the "meaning" of a property for a control. Por ejemplo, el ComboBox control debe definir el significado de la Background propiedad dentro de ComboBox.For example, the ComboBox control should define the meaning of the Background property within ComboBox. Los estilos predeterminados del control deben intentar seguir la semántica definida en ese documento en todos los temas.The default styles for your control should attempt to follow the semantics defined in that document across all themes. Por otro lado, los usuarios del control deben ser conscientes de que la semántica de la propiedad puede cambiar de un tema a otro.Control users, on the other hand, should be aware that property semantics can change from theme to theme. En algunos casos, es posible que una propiedad determinada no pueda expresarse dentro de las restricciones visuales requeridas por un tema concreto.In certain cases, a given property may not be expressible under the visual constraints required by a particular theme. (Por ejemplo, el tema Clásico no tiene un solo borde en el que Thickness se puede aplicar a muchos controles).(The Classic theme, for example, does not have a single border to which Thickness can be applied for many controls.)

  • Los estilos de temas no necesitan tener una semántica de desencadenadores coherente en todos los temas.Theme styles do not need to have consistent trigger semantics across all themes. El comportamiento expuesto por un estilo de control mediante desencadenadores o animaciones puede variar de un tema a otro.The behavior exposed by a control style through triggers or animations may vary from theme to theme. Los usuarios del control deben ser conscientes de que un control no usará necesariamente el mismo mecanismo para lograr un comportamiento concreto en todos los temas.Control users should be aware that a control will not necessarily employ the same mechanism to achieve a particular behavior across all themes. Un tema, por ejemplo, puede usar una animación para expresar el comportamiento de selección mediante movimiento del mouse mientras que otro tema usa un desencadenador.One theme, for example, may use an animation to express hover behavior where another theme uses a trigger. Esto puede provocar incoherencias en la conservación del comportamiento en los controles personalizados.This can result in inconsistencies in behavior preservation on customized controls. (Cambiar la propiedad de segundo plano, por ejemplo, podría no afectar al estado de selección mediante movimiento del mouse del control si dicho estado se expresa mediante un desencadenador.(Changing the background property, for example, might not affect the hover state of the control if that state is expressed using a trigger. Sin embargo, si el estado se implementa utilizando una animación, cambiar a segundo plano podría interrumpir irreparablemente la animación y, por lo tanto, la transición de estado).However, if the hover state is implemented using an animation, changing to background could irreparably break the animation and therefore the state transition.)

  • Los estilos de temas no necesitan tener una semántica de "diseño" coherente en todos los temas.Theme styles do not need to have consistent "layout" semantics across all themes. Por ejemplo, el estilo predeterminado no necesita garantizar que un control puede ocupar el mismo tamaño en todos los temas o garantizar que un control tendrá los mismos márgenes de contenido o espaciado interno en todos los temas.For example, the default style does not need to guarantee that a control will occupy the same amount of size in all themes or guarantee that a control will have the same content margins / padding across all themes.

Vea tambiénSee also