wpf data-binding architecture mvvm dependency-properties

wpf - INotifyPropertyChanged vs. DependencyProperty en ViewModel



data-binding architecture (14)

¿Es realmente una buena idea darle las dependencias de ViewModel a WPF?

.NET 4.0 tendrá System.Xaml.dll, por lo que no tendrá que depender de un marco arbitrario para utilizarlo. Ver el post de Rob Relyea sobre su sesión de PDC.

Mi toma

XAML es un lenguaje para describir objetos, y WPF es un marco cuyos objetos descritos son elementos de IU.

Su relación es similar a C #, un lenguaje para describir la lógica, y .NET, un marco que implementa tipos particulares de lógica.

El propósito de XAML son los gráficos de objetos declarativos. Las tecnologías W * F son excelentes candidatos para este paradigma, pero XAML existe independientemente de ellos.

XAML y todo el sistema de dependencia se implementaron como pilas separadas para WF y WPF, probablemente para aprovechar la experiencia de diferentes equipos sin crear una dependencia (sin intención de juego de palabras) entre ellos.

Al implementar el ViewModel en una aplicación WPF de arquitectura Modelo-View-ViewModel, parece que hay dos opciones principales de cómo convertirlo en un enlace de datos. He visto implementaciones que usan DependencyProperty para las propiedades con las que se va a enlazar la Vista y he visto que ViewModel implementa INotifyPropertyChanged en INotifyPropertyChanged lugar.

Mi pregunta es ¿cuándo debería preferir una sobre la otra? ¿Hay diferencias de rendimiento? ¿Es realmente una buena idea darle las dependencias de ViewModel a WPF? ¿Qué más debo tener en cuenta al tomar la decisión de diseño?


Creo que DependencyProperty e INotifyPropertyChanged se usan para dos cosas diferentes en Binding: el primero para permitir que una propiedad sea un objetivo de un enlace y reciba la entrada de otra propiedad (use {Binding ...} para establecer la propiedad), el último cuando desee que el valor de una propiedad se utilice como fuente de un enlace (nombre en la expresión de ruta de enlace). Así que la elección es meramente técnica.



Desde el punto de vista de la expresividad, disfruto mucho usando las propiedades de dependencia y me estremezco al pensar en INotifyPropertyChanged . Aparte de los nombres de propiedades de string y las posibles fugas de memoria debidas a la suscripción de eventos, INotifyPropertyChanged es un mecanismo mucho más explícito.

Las propiedades de dependencia implican "cuando esto, haga eso" utilizando metadatos estáticos de fácil comprensión. Es un enfoque declarativo que consigue mi voto por la elegancia.


Kent escribió un interesante blog sobre este tema: Ver modelos: POCO versus DependencyObjects .

Breve resumen:

  1. DependencyObjects no están marcados como serializables
  2. La clase DependencyObject anula y sella los métodos Equals () y GetHashCode ()
  3. Un objeto DependencyObject tiene afinidad de subprocesos: solo se puede acceder al subproceso en el que se creó.

Prefiero el enfoque POCO. Una clase base para PresentationModel (también conocido como ViewModel) que implementa la interfaz INotifyPropertyChanged se puede encontrar aquí: http://compositeextensions.codeplex.com


La elección se basa totalmente en la lógica de su negocio y el nivel de abstracción de la interfaz de usuario. Si no quieres una buena separación, entonces DP funcionará para ti.

DependencyProperties se aplicará principalmente en el nivel de VisualElements, por lo que no será una buena idea si creamos una gran cantidad de DP para cada uno de nuestros requisitos comerciales. También hay un costo mayor para DP que un INotifyPropertyChanged. Cuando diseñe un WPF / Silverlight, intente diseñar la interfaz de usuario y ViewModel totalmente separados para que en cualquier momento podamos cambiar los controles de diseño e interfaz de usuario (según el tema y los estilos)

Consulte también esta publicación: https://.com/questions/275098/what-applications-could-i-study-to-understand-datamodel-view-viewmodel . El enlace tiene una gran cantidad de referencias al patrón Model-View-ViewModel, que es muy relevante para esta discusión.


Las propiedades de dependencia están diseñadas para admitir el enlace (como destino) en los elementos de la interfaz de usuario, no como una fuente para el enlace de datos, aquí es donde entra INotifyProperty. Desde un punto de vista puro, no debe usar DP en un ViewModels.

"Para ser el origen de un enlace, una propiedad no necesita ser una propiedad de dependencia; puede usar cualquier propiedad CLR como un origen de enlace. Sin embargo, para ser el objetivo de un enlace, la propiedad debe ser una propiedad de dependencia. Para que un enlace unidireccional o bidireccional sea efectivo, la propiedad de origen debe admitir las notificaciones de cambios que se propagan al sistema de enlace y, por lo tanto, al destino. Para las fuentes de enlace de CLR personalizadas, esto significa que la propiedad debe admitir INotifyPropertyChanged. Las colecciones deben admitir INotifyCollectionChanged. "

No se pueden serializar todos los objetos de dependencia (esto podría obstaculizar el uso de ViewModels y DTO (POCO)).

Hay diferencias entre DP dentro de Silverlight en comparación con WPF.

http://msdn.microsoft.com/en-us/library/cc221408(v=VS.95).aspx

http://msdn.microsoft.com/en-us/library/cc903933(VS.95).aspx


Las propiedades de dependencia son el pegamento de la creación de control personalizado. Si está interesado en usar Intelli-sense para mostrar sus propiedades en la ventana de propiedades en el tiempo de diseño de XAML, debe usar las propiedades de Dependencia. INPC nunca mostrará una propiedad en la ventana de propiedades en tiempo de diseño.


Parece que las Propiedades de dependencia se deben usar en los controles que cree, como los Botones. Para usar las propiedades en XAML y usar todas las características de WPF, esas propiedades deben ser Propiedades de dependencia.

Sin embargo, su ViewModel está mejor usando INotifyPropertyChanged. El uso de INotifyPropertyChanged le dará la capacidad de tener lógica getter / setter si lo necesita.

Recomiendo revisar la versión de Josh Smith de una clase base para un ViewModel que ya implementa INotifyPropertyChanged:

http://joshsmithonwpf.wordpress.com/2007/08/29/a-base-class-which-implements-inotifypropertychanged/

Creo que este es un excelente ejemplo de cómo hacer un modelo de vista.


Prefiero un enfoque más directo, sobre el que escribí en el modelo de presentación sin INotifyPropertyChanged . Utilizando una alternativa al enlace de datos, puede enlazar directamente a las propiedades de CLR sin ningún código de contabilidad. Simplemente escribe código .NET antiguo en su Modelo de Vista, y se actualiza cuando cambia su Modelo de Datos.


Si desea exponer las propiedades a otros controles, debe usar las propiedades de dependencia ... Pero buena suerte porque tardan un tiempo en averiguar ...


Solo hay una cosa por qué preferir DependencyObject : Binding funcionará mejor. Simplemente intente un ejemplo con ListBox y TextBox , INotifyPropertyChanged lista con datos de la propiedad INotifyPropertyChanged contra DependencyProperty y edite el elemento actual de TextBox ...


Yo también tuve que considerar esta decisión recientemente.

Descubrí que el mecanismo INotifyPropertyChanged se adaptaba mejor a mis necesidades porque me permitía pegar mi GUI a un marco de lógica empresarial existente sin duplicar el estado. El marco que estaba usando tenía su propio patrón de observador y era fácil enviar un nivel de notificación al siguiente. Simplemente tuve una clase que implementó la interfaz de observador desde mi marco de lógica empresarial y la interfaz INotifyPropertyChanged.

Con DP no puede definir el backend que almacena el estado usted mismo. Hubiera tenido que dejar que .net almacenara en caché una copia de cada elemento del estado al que estaba vinculado. Esto parecía una sobrecarga innecesaria, mi estado es grande y complicado.

Así que aquí encontré INotifyPropertyChanged mejor para exponer las propiedades de la lógica de negocios a la GUI.

Dicho esto, cuando necesitaba un widget de GUI personalizado para exponer una propiedad y para que los cambios en esa propiedad afectaran a otros widgets de GUI, DP resultó ser la solución simple.

Así que allí encontré a DP útil para la notificación de GUI a GUI.


INotifyPropertyChanged cuando se usa también le brinda la posibilidad de agregar más lógica en el código de sus captadores y configuradores de sus propiedades.

Ejemplo de DependencyProperty :

public static DependencyProperty NameProperty = DependencyProperty.Register( "Name", typeof( String), typeof( Customer ) ); public String Name { set { SetValue( NameProperty, value ); } get { return ( String ) GetValue( NameProperty ); } }

En su captador y configurador --- todo lo que puede hacer es simplemente llamar a SetValue y GetValue respectivamente, b / c en otras partes del marco al que no se llama el captador / definidor, en su lugar, llama directamente a SetValue, GetValue, por lo que su lógica de propiedad no ser ejecutado de forma fiable.

Con INotifyPropertyChanged , define un evento:

public event PropertyChangedEventHandler PropertyChanged;

Y luego simplemente tenga cualquier lógica en cualquier parte de su código, luego llame:

// ... // Something cool... // ... if( this.PropertyChanged != null ) { PropertyChanged( this, new PropertyChangedEventArgs( "Name" ) ); } // More cool stuff that will reliably happen...

Esto podría ser en un getter / setter, o en cualquier otro lugar.