Optimizar el rendimiento: Enlace de datos

El enlace de datos de Windows Presentation Foundation (WPF) ofrece una manera sencilla y coherente de que las aplicaciones presenten datos e interactúen con ellos. Los elementos se pueden enlazar a datos desde una variedad de orígenes de datos en forma de objetos CLR y XML.

En este tema se proporcionan recomendaciones de rendimiento del enlace de datos.

Cómo se resuelven las referencias de enlace de datos

Antes de tratar los problemas de rendimiento del enlace de datos, vale la pena explorar cómo el motor de enlace de datos de Windows Presentation Foundation (WPF) resuelve las referencias de objeto para el enlace.

El origen de un enlace de datos de Windows Presentation Foundation (WPF) puede ser cualquier objeto CLR. Puede enlazar a propiedades, subpropiedades o indizadores de un objeto CLR. Las referencias de enlace se resuelven utilizando la reflexión de Microsoft .NET Framework o un ICustomTypeDescriptor. Estos son tres métodos para resolver las referencias de objeto para el enlace.

El primer método implica el uso de reflexión. En este caso, el objeto PropertyInfo se usa para detectar los atributos de la propiedad y proporcionar acceso a los metadatos de la propiedad. Al usar la interfaz ICustomTypeDescriptor, el motor de enlace de datos usa esta interfaz para obtener acceso a los valores de propiedad. La interfaz ICustomTypeDescriptor es especialmente útil en casos donde el objeto no tiene un conjunto de propiedades estático.

Las notificaciones de cambios de propiedades pueden proporcionarse implementando la interfaz INotifyPropertyChanged o utilizando las notificaciones de cambios asociadas a la interfaz TypeDescriptor. Sin embargo, la estrategia preferida para implementar notificaciones de cambio de propiedad es usar INotifyPropertyChanged.

Si el objeto de origen es un objeto CLR y la propiedad de origen es una propiedad CLR, el motor de enlace de datos de Windows Presentation Foundation (WPF) debe usar primero la reflexión en el objeto de origen para obtenerTypeDescriptor y, a continuación, consultar para obtener PropertyDescriptor. Esta secuencia de operaciones de reflexión es potencialmente muy lenta, desde una perspectiva de rendimiento.

El segundo método para resolver las referencias de objeto implica un objeto de origen CLR que implementa la interfaz INotifyPropertyChanged y una propiedad de origen que es una propiedad CLR. En este caso, el motor de enlace de datos usa la reflexión directamente en el tipo de origen y obtiene la propiedad necesaria. No es el método óptimo, pero tendrá un costo menor en los requisitos del conjunto de trabajo comparado con el primer método.

El tercer método para resolver las referencias de objeto implica un objeto origen que es un DependencyObject y una propiedad de origen que es un DependencyProperty. En este caso, el motor de enlace de datos no necesita usar la reflexión. En su lugar, el motor de propiedad y el motor de enlace de datos resuelven juntos la referencia de propiedad por separado. Este es el método óptimo para resolver las referencias de objeto que se usa para el enlace de datos.

La siguiente tabla compara la velocidad de enlace de datos de la propiedad Text de mil elementos TextBlock utilizando estos tres métodos.

Enlazar la propiedad de texto de TextBlock Tiempo de enlace (ms) Tiempo de representación, incluido el enlace (ms)
Para una propiedad de un objeto CLR 115 314
Para una propiedad de un objeto CLR que implementa INotifyPropertyChanged 115 305
Para un DependencyProperty de un DependencyObject. 90 263

Enlazar a objetos CLR grandes

Hay un impacto significativo en el rendimiento al enlazar datos a un único objeto CLR con miles de propiedades. Puede minimizar este impacto si divide el objeto único en varios objetos CLR con menos propiedades. En la tabla se muestran los tiempos de enlace y representación para el enlace de datos de un único objeto CLR grande frente a varios objetos más pequeños.

Enlace de datos de 1000 objetos TextBlock Tiempo de enlace (ms) Tiempo de representación, incluido el enlace (ms)
Para una objeto CLR con 1000 propiedades 950 1200
Para 1000 objetos CLR con una propiedad 115 314

Enlazar a ItemsSource

Considere un escenario en el que tiene un objeto CLR List<T> que contiene una lista de empleados que desea mostrar en un ListBox. Para crear una correspondencia entre estos dos objetos, vincularía su lista de empleados a la propiedad ItemsSource del ListBox. Sin embargo, suponga que tiene un nuevo empleado que se incorpora al grupo. Es posible que piense que, para insertar esta nueva persona en los valores ListBox enlazados, simplemente bastaría con agregarla a la lista de empleados y esperaría que el motor de enlace de datos reconociera el cambio automáticamente. Sin embargo, eso no es correcto, ya que, en realidad, el cambio no se reflejará automáticamente en el control ListBox. Esto ocurre porque el objeto CLR List<T> no genera automáticamente un evento cambiado de colección. Para conseguir que el ListBox recoja los cambios, tendría que volver a crear su lista de empleados y volver a adjuntarla a la propiedad ItemsSource del ListBox. Aunque esta solución funciona, supone un impacto enorme en el rendimiento. Cada vez que se reasigna el ItemsSource de ListBox a un nuevo objeto, el ListBox genera primero sus elementos anteriores y regenera toda su lista. El impacto en el rendimiento se magnifica si su ListBox se asigna a un complejo DataTemplate.

Una solución muy eficaz a este problema es hacer que su lista de empleados sea un ObservableCollection<T>. Un objeto ObservableCollection<T> plantea una notificación de cambio que el motor de enlace de datos puede recibir. El evento agrega o quita un elemento de un control ItemsControl sin necesidad de volver a generar toda la lista.

En la tabla siguiente se muestra el tiempo necesario para actualizar el control ListBox (con la virtualización de interfaz de usuario desactivada) cuando se agrega un elemento. El número de la primera fila representa el tiempo transcurrido cuando el objeto CLR List<T> está vinculado al elemento ListBox de ItemsSource. El número de la segunda fila representa el tiempo transcurrido cuando un ObservableCollection<T> está enlazado al ItemsSource del elemento ListBox. Obsérvese el importante ahorro de tiempo que supone la estrategia de enlace de datos ObservableCollection<T>.

Enlace de datos de ItemsSource Tiempo de actualización para 1 elemento (ms)
Para un objeto CLR List<T> 1656
Para un ObservableCollection<T> 20

Enlazar IList a ItemsControl no IEnumerable

Si puede elegir entre enlazar un IList<T> o un IEnumerable a un objeto ItemsControl, elija el objeto IList<T>. Enlazar IEnumerable a un ItemsControl obliga a WPF a crear un objeto contenedor IList<T>, lo que significa que su rendimiento se ve afectado por la sobrecarga innecesaria de un segundo objeto.

No convierta objetos CLR a XML solamente para enlazar datos.

WPF permite enlazar datos a contenido XML. Sin embargo, el enlace de datos al contenido XML es más lento que el enlace de datos a objetos CLR. No convierta datos de objeto CLR a XML si la única finalidad es el enlace de datos.

Vea también