2010-11-04 12 views
8

Por lo que desarrollo la aplicación WPF con MVVM, nunca expongo el modelo a través de la propiedad pública de viewmodel. De todos modos, después de venir al mundo de Silverlight y WCF RIA, encontré un nuevo método para lograr la validación de datos, dicho por el atributo Requerido. (hay otros atributos también)¿Por qué no es bueno exponer el Modelo a través de ViewModel en Silverlight MVVM?

Esta vez, en lugar de crear una lógica de validación dentro del modelo de vista, puedo hacer casi la lógica de validación dentro del modelo mismo.

public class TestUserPM { 
    [Key] 
    public int ID { get; set; } 

    [Required] 
    public string FirstName { get; set; } 

    [Required] 
    public string Email { get; set; } 
} 

Después de eso, todo lo que necesito en el modelo de vista es exponer la propiedad pública del tipo de TestUserPM y dejó Ver uniéndose directamente al modelo.

Creo que esta no es una solución elegante, pero puede funcionar y no es necesario crear una validación tediosa dentro de la propiedad viewmodel.

¿Hay algún inconveniente de este método?

Actualización 1

simplemente me encontré con 1 abajo del lado, puede ser que tiene solución por ahí. Quiero vincular el Comando de Botón, por ejemplo, el botón Guardar en Comando en el Modelo de Vista, pero este botón se puede ejecutar solo si todas las informaciones son válidas. Desde mi experiencia con WPF MVVM, que tengo clase de ayuda, llamaré al OnCanExecuteChanged() dentro de public string this[string columnName] de IDataErrorInfo.

¿Cómo puedo manejar este tipo de requisitos?

Respuesta

10

Expongo el modelo a través de ViewModel todo el tiempo, solo para mantener las cosas simples y no repetirme (DRY).

Lo único que evita la necesidad de agregar propiedades en el modelo para adaptarse a la interfaz de usuario (como señala Benjamin), es mantener el modelo como propiedad de viewModel, para que pueda agregar propiedades al viewModel, sin ensuciar el modelo.

es decir: El modelo de vista es el DataContext y tiene una propiedad Modelo devolver el modelo

<TextBlock Text={Binding Path=Model.Name} /> 
<TextBlock Text={Binding Path=Model.Address} /> 
+2

Hago lo mismo. ViewModel está aquí para exponer y adaptar el Modelo a la Vista. –

+0

La idea de usar el modelo directamente viola la regla de encapsulación porque nadie debería hacer 'MyObject.Child.ChildChild.NChild.SomeProperty'. También es una vez más la separación entre el Modelo y la Vista, porque si cambias el Nombre de la propiedad en tu Modelo, tienes que hacerlo en tu Vista/'s – WiiMaxx

4

El principal problema que veo es que su modelo (que podría ser un objeto comercial), debe adaptarse a la interfaz de usuario. Podría afectar mucho a otra interfaz de usuario o capa empresarial.

Puede imaginar varias UI con diferentes niveles de validaciones en el mismo objeto. Esto no es posible con tu ejemplo.

1

Es correcto utilizar la validación mediante anotación en Silverlight, en lugar de rellenar un ViewModel con código.

En el caso de alguna regla de validación especial, puede crear validadores personalizados y decorar los miembros con [CustomValidation ...], lo que mantendrá la validación lejos del ViewModel.

En cualquier caso, las reglas comerciales que describe generalmente se comparten entre vistas. La validación específica, para vistas de casos especiales, se puede agregar en los controladores.

Como un punto general: un ViewModel es un objeto relativamente tonto para contener valores para una vista. Si comienza a encontrar que está agregando lógica, controladores de eventos y otros, probablemente debería considerar introducir un objeto de controlador ... aunque no haya C en MVVM :)

+0

acabo de leer desde documentos y que no entiendo, ¿por qué tenemos que inyectar modelo de vista similar directamente de servicio? Esta es una tarea relacionada con la interfaz de usuario, debe estar en el nivel de interfaz de usuario, no en el servicio. (en mi opinión) Básicamente esto significa que tengo que poner todo en servicio, tan extraño para mí. :) – Anonymous

+0

@In The Pink: Lamento que no entiendo su pregunta (¿a qué servicio se refiere, un servicio de RIA?). ViewModel es la interfaz de usuario, pero los modelos de datos que expone son objetos comerciales llenados desde un servicio web. Con los servicios de RIA, la validación puede ocurrir tanto en el lado del cliente como en el del servicio. –

1

Para exponer modelo en modelo de vista, es necesario preparar el modelo para adaptar la vista, así que debe contaminar el Modelo con vista al código específico:

  • Notificar propiedad apoyar el cambio
  • error
  • de datos Información del soporte (Validación interior)
  • soporte editable .

Es necesario no contaminar su modelo con otra cosa, el modelo perfecto debe tener dependencias mínimas con otra biblioteca, por lo tanto se puede compartir en la misma aplicación con diferentes plataformas (asp.net, móvil, mono, winform, wpf, etc.). O para actualizar/degradar.

todos modos ..

me hizo una small WPF application uNhAddins (aún no terminado), he utilizado, NHibernate, Castillo a lo construyó. No digo que sea la mejor solución, pero estoy muy contento de trabajar con ella. Primero revise el código y luego vea la separación de Entidad, Lógica de validación, Lógica empresarial. La separación del ensamblaje se diseñó para minimizar la dependencia entre la aplicación central, la interfaz de usuario y la lógica de la aplicación.

4

El problema es que los demás han dicho que no se puede adaptar a la vista. Sin embargo, a menudo no quiero repetirme, como también dijo Eduardo con la exposición del modelo a la que se puede vincular. Considero que esa solución es un poco no coherente cuando se quiere alterar un valor para la vista; algunos serían vinculantes como "Model.Name" y otros simplemente como "Name" para la propiedad alterada, y algunos escenarios simplemente se ganarían ' t trabaja de esa manera.

Mi solución es crear una clase ViewModelProxy donde puede reenviar propiedades de otra clase y obtener notificaciones de propiedad de forma gratuita. Se hace con bastante facilidad derivando DynamicObject (dejé fuera notificación de código, IDataerror, etc.). Lo mejor de todo es que todas las propiedades de Data se reenvían, si implementa/anula una propiedad a la que se vinculará, de modo que no tiene que repetir el código y tiene una opción sensata para usar DynamicObject.

public class ViewModelProxy<T> : DynamicObject, INotifyPropertyChanged 

public T Data { get; set; } 

private PropertyInfo[] objectProperties; 
private PropertyInfo[] ObjectProperties 
{ 
    get 
    { 
    if (objectProperties == null) 
     objectProperties = typeof(T).GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); 
    return objectProperties; 
    } 
} 
public override bool TryGetMember(GetMemberBinder binder, out object result) 
{ 
    var pinfo = ObjectProperties.FirstOrDefault((pi) => pi.Name == binder.Name); 

    if (pinfo != null) 
    { 
    result = Data != null ? pinfo.GetValue(Data, null) : null; 
    return true; 
    } 
    else 
    return base.TryGetMember(binder, out result); 
} 


public override bool TrySetMember(SetMemberBinder binder, object value) 
{ 
    var pinfo = ObjectProperties.FirstOrDefault((pi) => pi.Name == binder.Name); 

    if (pinfo != null) 
    { 
    if (Data != null) 
     pinfo.SetValue(Data, value, null); 
    RaisePropertyChanged(binder.Name); 
    return true; 
    } 
    else 
    return base.TrySetMember(binder, value); 
} 

}

+0

¿Y cómo es el rendimiento? Parece que la ralentizará un poco ... ¿No? –

+0

El rendimiento es bueno. Por supuesto, hay una pequeña sobrecarga, pero las llamadas de reflexión no son tan costosas. Si tiene muchas propiedades, puede cambiar la búsqueda de matriz con una búsqueda de diccionario. –

Cuestiones relacionadas