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.
En este tema se proporciona una visita guiada a la jerarquía de clases de Windows Presentation Foundation (WPF). Trata la mayoría de los subsistemas principales de WPF y describe cómo interactúan. También detalla algunas de las opciones realizadas por los arquitectos de WPF.
System.Object
El modelo de programación de WPF principal se expone mediante código administrado. Al principio de la fase de diseño de WPF hubo varios debates sobre dónde debe dibujarse la línea entre los componentes administrados del sistema y los no administrados. CLR proporciona una serie de características que hacen que el desarrollo sea más productivo y sólido (incluida la administración de memoria, el control de errores, el sistema de tipos común, etc.), pero se ven a un costo.
Los componentes principales de WPF se muestran en la ilustración siguiente. Las secciones rojas del diagrama (PresentationFramework, PresentationCore y milcore) son las principales partes de código de WPF. De estos, solo uno es un componente no administrado: milcore. Milcore está escrito en código no administrado para permitir una estrecha integración con DirectX. Toda la visualización en WPF se realiza a través del motor DirectX, lo que permite una representación eficaz de hardware y software. WPF también requería un control fino sobre la memoria y la ejecución. El motor de composición de milcore es extremadamente sensible al rendimiento, lo que requirió renunciar a muchas ventajas del CLR para mejorar el rendimiento.
La comunicación entre las partes administradas y no administradas de WPF se describe más adelante en este tema. El resto del modelo de programación administrada se describe a continuación.
System.Threading.DispatcherObject
La mayoría de los objetos de WPF derivan de DispatcherObject, que proporciona las construcciones básicas para tratar con simultaneidad y subprocesos. WPF se basa en un sistema de mensajería implementado por el distribuidor. Esto funciona de forma similar a la conocida bomba de mensajes Win32; de hecho, el distribuidor de WPF usa mensajes User32 para realizar llamadas entre subprocesos.
Hay realmente dos conceptos básicos que comprender al analizar la simultaneidad en WPF: la afinidad entre distribuidor y subproceso.
Durante la fase de diseño de WPF, el objetivo era pasar a un único subproceso de ejecución, pero a un modelo que no tiene afinidad con un subproceso. La afinidad de subprocesos se produce cuando un componente usa la identidad del subproceso en ejecución para almacenar algún tipo de estado. La forma más común de esto es usar el almacén local de subprocesos (TLS) para almacenar el estado. La afinidad de subproceso requiere que cada subproceso lógico de ejecución sea propiedad de solo un subproceso físico en el sistema operativo, lo que puede consumir memoria. Al final, el modelo de subprocesos de WPF se mantuvo sincronizado con el modelo de subproceso User32 existente de ejecución de un único subproceso con afinidad de subproceso. La razón principal de esto fue la interoperabilidad: sistemas como OLE 2.0, el Portapapeles e Internet Explorer requieren la ejecución con afinidad de un solo hilo (STA).
Dado que tiene objetos con subprocesos STA, necesita una manera de comunicarse entre subprocesos y validar que se encuentra en el subproceso correcto. Aquí yace el papel del despachador. El distribuidor es un sistema básico de distribución de mensajes, con múltiples colas prioritarias. Algunos ejemplos de mensajes incluyen notificaciones de entrada sin procesar (ratón movido), funciones de marco (diseño) o comandos de usuario (ejecute este método). Al derivar de DispatcherObject, se crea un objeto CLR que tiene comportamiento STA y se le asigna un puntero a un dispachador en el momento de su creación.
System.Windows.DependencyObject
Una de las filosofías arquitectónicas principales utilizadas en el desarrollo de WPF era preferir las propiedades sobre los métodos o eventos. Las propiedades son declarativas y permiten especificar más fácilmente la intención en lugar de la acción. Esto también admite un sistema controlado por modelos o controlado por datos para mostrar contenido de la interfaz de usuario. Esta filosofía tenía el efecto previsto de crear más propiedades a las que se podía enlazar, con el fin de controlar mejor el comportamiento de una aplicación.
Para lograr más integración del sistema impulsado por propiedades, se necesitaba un sistema de propiedades más rico que el que proporciona el CLR. Un ejemplo sencillo de esta riqueza es las notificaciones de cambio. Para habilitar el enlace bidireccional, necesita ambos lados del enlace para admitir la notificación de cambios. Para tener un comportamiento asociado a los valores de propiedad, debe recibir una notificación cuando cambie el valor de propiedad. Microsoft .NET Framework tiene una interfaz, INotifyPropertyChange, que permite que un objeto publique notificaciones de cambios, pero es opcional.
WPF proporciona un sistema de propiedades más completo, derivado del DependencyObject tipo . El sistema de propiedades es realmente un sistema de propiedades de "dependencia" en que realiza un seguimiento de las dependencias entre expresiones de propiedad y vuelve a validar automáticamente los valores de propiedad cuando cambian las dependencias. Por ejemplo, si tiene una propiedad que hereda (como FontSize), el sistema se actualiza automáticamente si la propiedad cambia en un elemento primario de un elemento que hereda el valor.
La base del sistema de propiedades de WPF es el concepto de una expresión de propiedad. En esta primera versión de WPF, se cierra el sistema de expresiones de propiedad y todas las expresiones se proporcionan como parte del marco de trabajo. Las expresiones son el motivo por el que el sistema de propiedades no tiene codificación rígida de enlace, estilo o herencia de datos, sino que se proporciona en capas posteriores dentro del marco.
El sistema de propiedades también proporciona un almacenaje disperso de valores de propiedad. Dado que los objetos pueden tener docenas (si no cientos) de propiedades, y la mayoría de los valores están en su estado predeterminado (heredado, establecido por estilos, etc.), no todas las instancias de un objeto deben tener el peso completo de cada propiedad definida en él.
La nueva característica final del sistema de propiedades es la noción de propiedades adjuntas. Los elementos WPF se basan en el principio de composición y reutilización de componentes. A menudo, es el caso de que algunos elementos contenedores (como un Grid elemento de diseño) necesiten datos adicionales en los elementos secundarios para controlar su comportamiento (como la información de fila o columna). En lugar de asociar todas estas propiedades con cada elemento, se permite que cualquier objeto proporcione definiciones de propiedad para cualquier otro objeto. Esto es similar a las características de "expando" de JavaScript.
System.Windows.Media.Visual
Con un sistema definido, el siguiente paso es dibujar píxeles en la pantalla. La Visual clase proporciona para crear un árbol de objetos visuales, cada uno de los cuales contiene opcionalmente instrucciones de dibujo y metadatos sobre cómo representar esas instrucciones (recorte, transformación, etc.). Visual está diseñado para ser extremadamente ligero y flexible, por lo que la mayoría de las funcionalidades no están expuestas a través de una API pública y dependen en gran parte de las funciones de devolución de llamada protegidas.
Visual es realmente el punto de entrada al sistema de composición de WPF. Visual es el punto de conexión entre estos dos subsistemas, la API administrada y el milcore no administrado.
WPF muestra los datos mediante el recorrido de las estructuras de datos no administradas administradas por milcore. Estas estructuras, denominadas nodos de composición, representan un árbol de visualización jerárquico con instrucciones de representación en cada nodo. Este árbol, que se muestra en el lado derecho de la ilustración siguiente, solo es accesible a través de un protocolo de mensajería.
Al programar WPF, se crean Visual elementos y tipos derivados, que se comunican internamente con el árbol de composición a través de este protocolo de mensajería. Cada Visual en WPF puede crear uno, ninguno o varios nodos de composición.
Hay un detalle arquitectónico muy importante que observar aquí: todo el árbol de objetos visuales y las instrucciones de dibujo se almacena en caché. En términos gráficos, WPF usa un sistema de representación retenido. Esto permite que el sistema vuelva a pintar a altas velocidades de actualización sin que el sistema de composición bloquee las devoluciones de llamada al código de usuario. Esto ayuda a evitar la aparición de una aplicación que no responde.
Otro detalle importante que no es realmente notable en el diagrama es cómo el sistema realmente realiza la composición.
En User32 y GDI, el sistema utiliza un sistema de recorte de modo inmediato. Cuando es necesario representar un componente, el sistema establece un límite de recorte fuera del cual el componente no puede tocar los píxeles y, a continuación, se pide al componente que pinte píxeles en ese cuadro. Este sistema funciona muy bien en sistemas con restricciones de memoria porque cuando algo cambia solo tiene que tocar el componente afectado: ningún componente contribuye nunca al color de un solo píxel.
El WPF utiliza un modelo de pintura llamado "algoritmo del pintor". Esto significa que, en lugar de recortar cada componente, se pide que cada componente se represente desde la parte posterior a la parte frontal de la pantalla. Esto permite que cada componente pinte sobre la pantalla del componente anterior. La ventaja de este modelo es que puede tener formas complejas y parcialmente transparentes. Con el hardware gráfico moderno de hoy, este modelo es relativamente rápido (que no fue el caso cuando se creó User32/ GDI).
Como se mencionó anteriormente, una filosofía principal de WPF es pasar a un modelo más declarativo y "centrado en propiedades" de programación. En el sistema visual, esto se muestra en un par de lugares interesantes.
En primer lugar, si piensa en el sistema gráfico de modo retenido, esto realmente se aleja de un modelo imperativo de tipo DrawLine/DrawLine, a un modelo orientado a datos: new Line()/new Line(). Este cambio a la representación controlada por datos permite expresar operaciones complejas en las instrucciones de dibujo mediante propiedades. Los tipos derivados de Drawing son efectivamente el modelo de objetos para la representación.
En segundo lugar, si evalúas el sistema de animación, verás que es casi completamente declarativo. En lugar de requerir que un desarrollador calcule la siguiente ubicación o el siguiente color, puede expresar animaciones como un conjunto de propiedades en un objeto de animación. Estas animaciones pueden expresar la intención del desarrollador o diseñador (mover este botón de aquí a allá en 5 segundos) y el sistema puede determinar la manera más eficaz de lograrlo.
System.Windows.UIElement
UIElement define subsistemas principales, como Diseño, Entrada y Eventos.
El diseño es un concepto básico en WPF. En muchos sistemas hay un conjunto fijo de modelos de diseño (HTML admite tres modelos para el diseño; flujo, absoluto y tablas) o ningún modelo para el diseño (User32 solo admite el posicionamiento absoluto). WPF comenzó con la suposición de que los desarrolladores y diseñadores querían un modelo de diseño flexible y extensible, que podría estar controlado por valores de propiedad en lugar de lógica imperativa. En el UIElement nivel, se introduce el contrato básico para el diseño: un modelo de dos etapas con Measure y Arrange pasos.
Measure permite que un componente determine cuánto tamaño le gustaría tomar. Se trata de una fase independiente de Arrange porque hay muchas situaciones en las que un elemento primario pedirá a un elemento secundario que mida varias veces para determinar su posición y tamaño óptimos. El hecho de que los elementos primarios pidan a los elementos secundarios que mida muestran otra filosofía clave de WPF: tamaño al contenido. Todos los controles de WPF admiten la capacidad de ajustar el tamaño al tamaño natural de su contenido. Esto facilita mucho la localización y permite un diseño dinámico de elementos a medida que se cambia el tamaño de las cosas. La Arrange fase permite que un padre posicione y determine el tamaño final de cada hijo.
A menudo se dedica mucho tiempo a hablar sobre el lado de salida de WPF y Visual los objetos relacionados. Sin embargo, también hay una gran cantidad de innovación en el lado de entrada. Probablemente el cambio más fundamental en el modelo de entrada para WPF es el modelo coherente por el que los eventos de entrada se enrutan a través del sistema.
La entrada se origina como una señal en un controlador de dispositivo en modo kernel y se enruta al proceso y subproceso correctos a través de un proceso intrincado que implica el kernel de Windows y User32. Una vez que el mensaje User32 correspondiente a la entrada se enruta a WPF, se convierte en un mensaje de entrada sin procesar de WPF y se envía al distribuidor. WPF permite convertir eventos de entrada sin procesar en varios eventos reales, lo que permite implementar características como "MouseEnter" en un nivel bajo del sistema con entrega garantizada.
Cada evento de entrada se convierte en al menos dos eventos: un evento de "vista previa" y el evento real. Todos los eventos de WPF tienen una noción de enrutamiento a través del árbol de elementos. Se dice que los eventos se "propagan" si atraviesan desde un objetivo hacia arriba en el árbol hasta la raíz, y se dice que se "transmiten mediante túnel" si comienzan en la raíz y descienden hacia un objetivo. Túnel de eventos de vista previa de entrada, lo que permite que cualquier elemento del árbol filtre o tome medidas en el evento. Los eventos normales (no en versión preliminar) se propagan desde el destino hasta la raíz.
Esta división entre el túnel y la fase de burbuja hace que la implementación de características como los aceleradores de teclado funcionen de forma coherente en un mundo compuesto. En User32 se implementan los aceleradores de teclado utilizando una única tabla global que contiene todos los aceleradores que se desee admitir (Ctrl+N para asignar a "Nuevo"). En el despachador de su aplicación llamarías a TranslateAccelerator, que examinaría los mensajes de entrada en User32 y determinaría si alguno coincide con un acelerador registrado. En WPF esto no funcionaría porque el sistema es totalmente "composable", cualquier elemento puede controlar y usar cualquier acelerador de teclado. Tener este modelo de dos fases para la entrada permite a los componentes implementar su propio "TranslateAccelerator".
Para seguir este paso, UIElement también presenta la noción de CommandBindings. El sistema de comandos de WPF permite a los desarrolladores definir la funcionalidad en términos de un punto de conexión de comandos que implementa ICommand. Los enlaces de comandos permiten a un elemento definir una asignación entre un gesto de entrada (Ctrl+N) y un comando (Nuevo). Tanto los gestos de entrada como las definiciones de comandos son extensibles y se pueden integrar juntos durante su uso. Esto hace que sea trivial, por ejemplo, permitir que un usuario final personalice los enlaces de clave que quieren usar dentro de una aplicación.
Hasta este punto del tema, las características "principales" de WPF: las características implementadas en el ensamblado PresentationCore han sido el foco. Al compilar WPF, una separación limpia entre las piezas fundamentales (como el contrato para el diseño con Measure y Arrange) y las partes del marco (como la implementación de un diseño específico como Grid) fue el resultado deseado. El objetivo era proporcionar un punto de extensibilidad bajo en la pila que permitiría a los desarrolladores externos crear sus propios frameworks cuando sea necesario.
System.Windows.FrameworkElement
FrameworkElement se puede examinar de dos maneras diferentes. Presenta un conjunto de directivas y personalizaciones en los subsistemas introducidos en capas inferiores de WPF. También presenta un conjunto de nuevos subsistemas.
La directiva principal introducida por FrameworkElement está en torno al diseño de la aplicación. FrameworkElement se basa en el contrato de diseño básico introducido por UIElement y añade el concepto de un "slot" de diseño que facilita a los autores de diseños mantener un conjunto coherente de semántica de diseño impulsada por propiedades. Las propiedades como HorizontalAlignment, VerticalAlignment, MinWidthy Margin (por nombrar algunos) proporcionan a todos los componentes derivados del FrameworkElement comportamiento coherente dentro de los contenedores de diseño.
FrameworkElement también proporciona una exposición más sencilla de la API a muchas características que se encuentran en las capas principales de WPF. Por ejemplo, FrameworkElement proporciona acceso directo a la animación a través del BeginStoryboard método . Storyboard proporciona una manera de escribir scripts para múltiples animaciones contra un conjunto de propiedades.
Los dos aspectos más críticos que FrameworkElement presentan son el enlace de datos y los estilos.
El subsistema de enlace de datos en WPF debe estar relativamente familiarizado con cualquier persona que haya usado Windows Forms o ASP.NET para crear una interfaz de usuario (UI) de aplicación. En cada uno de estos sistemas, hay una manera sencilla de expresar que desea que una o varias propiedades de un elemento determinado se enlacen a un fragmento de datos. WPF tiene soporte completo para la vinculación de propiedades, la transformación y la vinculación de listas.
Una de las características más interesantes del enlace de datos en WPF es la introducción de plantillas de datos. Las plantillas de datos permiten especificar mediante declaración cómo se debe visualizar un fragmento de datos. En lugar de crear una interfaz de usuario personalizada que se pueda enlazar a los datos, puede cambiar el problema y dejar que los datos determinen la presentación que se creará.
El estilo es realmente una forma de enlace de datos ligera. Con el estilo, puede enlazar un conjunto de propiedades de una definición compartida a una o varias instancias de un elemento. Los estilos se aplican a un elemento por referencia explícita (estableciendo la Style propiedad) o implícitamente asociando un estilo con el tipo CLR del elemento.
System.Windows.Controls.Control
La característica más importante del control es la creación de plantillas. Si piensa en el sistema de composición de WPF como un sistema de representación en modo retenido, la creación de plantillas permite a un control describir su representación de forma declarativa y parametrizada. Un ControlTemplate realmente no es más que un script para crear un conjunto de elementos secundarios, con vinculaciones a propiedades que ofrece el control.
Control proporciona un conjunto de propiedades de stock, Foreground, Background, Padding, para nombrar algunos, que los autores de plantillas pueden usar para personalizar la presentación de un control. La implementación de un control proporciona un modelo de datos y un modelo de interacción. El modelo de interacción define un conjunto de comandos (como Cerrar para una ventana) y enlaces a gestos de entrada (como hacer clic en la X roja en la esquina superior de la ventana). El modelo de datos proporciona un conjunto de propiedades para personalizar el modelo de interacción o personalizar la presentación (determinada por la plantilla).
Esta división entre el modelo de datos (propiedades), el modelo de interacción (comandos y eventos) y el modelo de visualización (plantillas) permite personalizar completamente la apariencia y el comportamiento de un control.
Un aspecto común del modelo de datos de controles es el modelo de contenido. Si observa un control como Button, verá que tiene una propiedad denominada "Content" de tipo Object. En Windows Forms y ASP.NET, esta propiedad normalmente sería una cadena, pero que limita el tipo de contenido que se puede colocar en un botón. El contenido de un botón puede ser una cadena simple, un objeto de datos complejo o un árbol de elementos completo. En el caso de un objeto de datos, la plantilla de datos se usa para construir una presentación.
Resumen
WPF está diseñado para permitirle crear sistemas de presentación dinámicos y controlados por datos. Cada parte del sistema está diseñada para crear objetos a través de conjuntos de propiedades que impulsan el comportamiento. El enlace de datos es una parte fundamental del sistema y se integra en cada capa.
Las aplicaciones tradicionales crean una pantalla y, a continuación, se enlazan a algunos datos. En WPF, todo sobre el control, cada aspecto de la pantalla, se genera mediante algún tipo de enlace de datos. El texto que se encuentra dentro de un botón se muestra creando un control compuesto dentro del botón y enlazando su presentación a la propiedad de contenido del botón.
Cuando empiece a desarrollar aplicaciones basadas en WPF, debería sentirse muy familiar. Puede establecer propiedades, usar objetos y enlazar datos de la misma manera que puede usar Windows Forms o ASP.NET. Con una investigación más profunda sobre la arquitectura de WPF, encontrará que existe la posibilidad de crear aplicaciones mucho más enriquecidas que tratan fundamentalmente los datos como el controlador principal de la aplicación.
Consulte también
- Visual
- UIElement
- ICommand
- FrameworkElement
- DispatcherObject
- CommandBinding
- Control
- Información general sobre el enlace de datos
- Diseño
- Visión general de animación
.NET Desktop feedback