Implementación de patrón de diseño de ViewModel usando DI en una arquitectura MVP-VM -- # campo con .net campo con dependency-injection campo con mvp campo con mvvm camp codereview Relacionados El problema

Implementing ViewModel design pattern using DI in a MVP-VM architecture


3
vote

problema

Español

Basado en esta respuesta: MVVM Implementación usando C # y Xaml , entiendo que mi vistmodel es algún tipo de envoltura para mi modelo .

Siendo un fanático de los principios sólidos y sólidos y , he hecho mi visualmodel modelo -depending.

CustomerDetailviewModel

  public class CustomerDetailViewModel : ViewModel<Customer> {     public CustomerDetailViewModel(Customer model) : base(model) { }      public bool AllRequiredInformationHasBeenProvided {         get {              return !string.IsNullOrWhiteSpace(Email)                 && !string.IsNullOrWhiteSpace(GivenName)                 && !string.IsNullOrWhiteSpace(Surname);         }     }      public string Email { get { return Model.Email; } set { setEmail(value); } }     public string GivenName { get { return Model.GivenName; } set { setGivenName(value); } }     public string Surname { get { return Model.Surname; } set { setSurname(value); } }      private void setEmail(string email) {         Model.Email = email;         RaisePropertyChangedFor(m => m.Email);     }      private void setGivenName(string givenName) {         Model.GivenName = givenName;         RaisePropertyChangedFor(m => m.GivenName);     }      private void setSurname(string surname) {         Model.Surname= surname;         RaisePropertyChangedFor(m => m.Surname);     } }   

personalmanagementviewmodel

  public class CustomerManagementViewModel : ViewModel<IList<Customer>>,  {     public CustomerManagementViewModel(IList<Customer> model) : base(model) { }      public Customer GetCurrent(int index) { return Model.ElementAt(index); }        }   

vismodel

  public abstract class ViewModel<M> : IViewModel<M> where M : class {     public ViewModel(M model) { Model = model; }      public virtual M Model { get { return model; } set { setModel(value); }      public event PropertyChangedEventHandler PropertyChanged;      protected virtual RaisePropertyChangedFor(Expression<Func<M, object>> propertyExpression) {         var expression = (MemberExpression)propertyExpression.Body;         if (expressionIsNoMemberExpression(expression)) return;         raisePropertyChangedFor(expression.Member.Name);     }      private void setModel(M value) {         if (value == null) throw new ArgumentNullException("Model");         model = value;         raisePropertyChangedFor("Model");     }      private M model; }   

iviewmodel

  public interface IViewModel<M> : INotifyPropertyChanged where M : class {     M Model { get; set; } }   

cliente

  public class Customer {     public string Email { get; set; }     public string GivenName { get { return givenName; } set { setGivenName(value); } }     public string Surname { get { return surname; } set { setSurname(value); } }      private void setGivenName(string givenName) {         if (givenName == null) throw new ArgumentNullException("GivenName");         if (string.IsNullOrWhiteSpace(givenName)) throw new ArgumentException("GivenName");         this.givenName = givenName;     }      private void setSurname(string surname) {         if (surname == null) throw new ArgumentNullException("Surname");         if (string.IsNullOrWhiteSpace(surname)) throw new ArgumentException("Surname");         this.surname = surname;     }      private string givenName;     private string surname; }   

Obviamente, el modelo puede cambiar a lo largo de la forma en que la propiedad 9988776655544335 es cambiable.

Uso de MVP-VM, pertenece al Presenter para cambiar el Model .

clienteDetailPresenter

  public class CustomerDetailPresenter      : Presenter<ICustomerDetailView<CustomerDetailViewModel>>     , ICustomerDetailUiHandler {     public CustomerDetailPresenter(ICustomerDetailView view)          : base(view) {          View.Handler = this;     }      public void ShowDetailsFor(Customer customer) {         View.ViewModel.Model = customer;         View.Show();     } }   

Entonces, mi clase compositor lo une por completo a través de la unión de la convención.

compositorroot

  public class CompositionRoot {     private CompositionRoot() { }      public static ComposeObjectGraph() {         var projectAssemblies =              GetProjectAssemblies(ProjectAssemblyKey, TestProjectAssemblyKey);         BindViewsFor(project, ViewKey, FormKey);         BindViewModelsFor(project, ViewModelKey);     }      private static void BindViewsFor(IEnumerable<Assembly> projectAssemblies         , string viewsKeyword         , string formsKeyword) {         kernel.Bind(services => services             From(projectAssemblies)             .SelectAllClasses()             .EndingWith(formsKeyword)             .BindSelect((type, baseType) => type                 .GetInterfaces()                 .Where(iface => iface.Name.EndsWith(viewsKeyword)                              && !iface.Name.Equals(string.Concat("I", viewsKeyword)))));     }      private static void BindViewModelsFor(IEnumerable<Assembly> projectAssemblies         , viewModelsKeyword) {          kernel.Bind(services => services              .From(projectAssemblies)              .SelectAllClasses()              .EndingWith(viewMoelsKeyword)              .BindToSelf());        }      private const string FormKey = "Form";     private const string ProjectAssemblyKey = "MyProject";     private const string TestProjectAssemblyKey = "Tests";     private const string ViewKey = "View";     private const string ViewModelKey = "ViewModel";      private static readonly IKernel kernel = new StandardKernel(); }   

Me gustaría tener algunos comentarios sobre cómo puedo simplificar mi código, o si estoy en la pista correcta.

Original en ingles

Based on this answer: MVVM implementation using C# and XAML, I understand that my ViewModel is some kind of a wrapper for my Model.

Being a fan of DI and SOLID principles, I have made my ViewModel Model-dependent.

CustomerDetailViewModel

public class CustomerDetailViewModel : ViewModel<Customer> {     public CustomerDetailViewModel(Customer model) : base(model) { }      public bool AllRequiredInformationHasBeenProvided {         get {              return !string.IsNullOrWhiteSpace(Email)                 && !string.IsNullOrWhiteSpace(GivenName)                 && !string.IsNullOrWhiteSpace(Surname);         }     }      public string Email { get { return Model.Email; } set { setEmail(value); } }     public string GivenName { get { return Model.GivenName; } set { setGivenName(value); } }     public string Surname { get { return Model.Surname; } set { setSurname(value); } }      private void setEmail(string email) {         Model.Email = email;         RaisePropertyChangedFor(m => m.Email);     }      private void setGivenName(string givenName) {         Model.GivenName = givenName;         RaisePropertyChangedFor(m => m.GivenName);     }      private void setSurname(string surname) {         Model.Surname= surname;         RaisePropertyChangedFor(m => m.Surname);     } } 

CustomerManagementViewModel

public class CustomerManagementViewModel : ViewModel<IList<Customer>>,  {     public CustomerManagementViewModel(IList<Customer> model) : base(model) { }      public Customer GetCurrent(int index) { return Model.ElementAt(index); }        } 

ViewModel

public abstract class ViewModel<M> : IViewModel<M> where M : class {     public ViewModel(M model) { Model = model; }      public virtual M Model { get { return model; } set { setModel(value); }      public event PropertyChangedEventHandler PropertyChanged;      protected virtual RaisePropertyChangedFor(Expression<Func<M, object>> propertyExpression) {         var expression = (MemberExpression)propertyExpression.Body;         if (expressionIsNoMemberExpression(expression)) return;         raisePropertyChangedFor(expression.Member.Name);     }      private void setModel(M value) {         if (value == null) throw new ArgumentNullException("Model");         model = value;         raisePropertyChangedFor("Model");     }      private M model; } 

IViewModel

public interface IViewModel<M> : INotifyPropertyChanged where M : class {     M Model { get; set; } } 

Customer

public class Customer {     public string Email { get; set; }     public string GivenName { get { return givenName; } set { setGivenName(value); } }     public string Surname { get { return surname; } set { setSurname(value); } }      private void setGivenName(string givenName) {         if (givenName == null) throw new ArgumentNullException("GivenName");         if (string.IsNullOrWhiteSpace(givenName)) throw new ArgumentException("GivenName");         this.givenName = givenName;     }      private void setSurname(string surname) {         if (surname == null) throw new ArgumentNullException("Surname");         if (string.IsNullOrWhiteSpace(surname)) throw new ArgumentException("Surname");         this.surname = surname;     }      private string givenName;     private string surname; } 

Obviously, the model might change along the way so that the IViewModel.Model property is changeable.

Using MVP-VM, it belongs to the Presenter to change the Model.

CustomerDetailPresenter

public class CustomerDetailPresenter      : Presenter<ICustomerDetailView<CustomerDetailViewModel>>     , ICustomerDetailUiHandler {     public CustomerDetailPresenter(ICustomerDetailView view)          : base(view) {          View.Handler = this;     }      public void ShowDetailsFor(Customer customer) {         View.ViewModel.Model = customer;         View.Show();     } } 

Then, my CompositionRoot class binds it altogether through convention binding.

CompositionRoot

public class CompositionRoot {     private CompositionRoot() { }      public static ComposeObjectGraph() {         var projectAssemblies =              GetProjectAssemblies(ProjectAssemblyKey, TestProjectAssemblyKey);         BindViewsFor(project, ViewKey, FormKey);         BindViewModelsFor(project, ViewModelKey);     }      private static void BindViewsFor(IEnumerable<Assembly> projectAssemblies         , string viewsKeyword         , string formsKeyword) {         kernel.Bind(services => services             From(projectAssemblies)             .SelectAllClasses()             .EndingWith(formsKeyword)             .BindSelect((type, baseType) => type                 .GetInterfaces()                 .Where(iface => iface.Name.EndsWith(viewsKeyword)                              && !iface.Name.Equals(string.Concat("I", viewsKeyword)))));     }      private static void BindViewModelsFor(IEnumerable<Assembly> projectAssemblies         , viewModelsKeyword) {          kernel.Bind(services => services              .From(projectAssemblies)              .SelectAllClasses()              .EndingWith(viewMoelsKeyword)              .BindToSelf());        }      private const string FormKey = "Form";     private const string ProjectAssemblyKey = "MyProject";     private const string TestProjectAssemblyKey = "Tests";     private const string ViewKey = "View";     private const string ViewModelKey = "ViewModel";      private static readonly IKernel kernel = new StandardKernel(); } 

I'd like to have some feedback on how I can simplify my code, or if I am on the right track.

              
         
         

Lista de respuestas

2
 
vote

Algunas cosas superficiales:

  1. Los modelos de su vista deben estar implementando INotifyPropertyChanged . Esto hará que sea más obvio que sus modelos aumentarán los eventos de cambio de propiedad. También el marco de vinculación de WPF verifica si una clase implementa esta interfaz y la utiliza si lo hace.

  2. Convención de nombres estándar para C # es PascalCase para los nombres de los métodos (privado o no generalmente no hace diferencia)

 

A few superficial things:

  1. Your view models should be implementing INotifyPropertyChanged. This will make it more obvious that your models will raise property change events. Also the WPF binding framework checks if a class implements this interface and makes use of it if it does so.

  2. Standard naming convention for C# is PascalCase for method names (private or not usually makes no difference)

 
 
     
     

Relacionados problema

1  Una compilación ViewModel con Reactiveui 8 para obtener imágenes web  ( A viewmodel build with reactiveui 8 to get web images ) 
Esta es una aplicación de práctica que construí para aprender RX.NET & AMP; Rxui. Sigue el patrón MVVM y está escrito en C # con WPF. aquí es un enlace a un...

1  Usando VUE para ayudar a formar validación con peso para la edad  ( Using vue to help form validation with weight for age ) 
Estoy refactorizando una página web muy antigua que calcula las dosis de los medicamentos de Bolus y Infusión para los niños de la edad prematura a la edad ad...

6  Vistas de grasa para editar imágenes  ( Fat viewmodels for editing images ) 
¿Cómo debo tratar con ViewModel s que son "grasas"? O debería simplemente aceptarlo a veces. Ejemplo: uno de mis ViewModel S (Edición de la página de la...

7  MV * Patrón para un juego de mesa  ( Mv pattern for a board game ) 
He hecho un pequeño juego en JavaScript, mientras se entera simultáneamente sobre el controlador de visualización modelo más popular. El juego es este, hay 3 ...

7  Ver base de modelo  ( View model base ) 
Necesitaba escribir código en WPF para un cliente. La solicitud se realiza con prisma (no mi decisión, ya tenían personas que trabajaban en ella), por lo que ...

3  Cargando subistemas de TreeView en el fondo  ( Loading sub items of treeview in background ) 
Estoy trabajando con un TreeView (Control predeterminado desde .NET Framework) que muestra datos hierachicales. Los datos están vinculados a la vista utiliz...

1  Elija aleatoriamente un juego ejecutable de una carpeta 2.0  ( Randomly choose a game executable from a folder 2 0 ) 
Después de preguntarle a Elija aleatoriamente un juego ejecutable de una carpeta < / a>, aplicé los cambios recomendados. También rediseñé el programa para h...

4  Insertar objeto de modelo de manera efectiva usando la entidad Framework  ( Insert model object effectively using entity framwork ) 
Tengo una aplicación MVVM de WPF. Tengo un modelo de cliente que es generado por un marco de entidad (primer enfoque de la base de datos) y un 99887766555443...

2  Establecer objetos para MVVM adecuados en Knockout  ( Structuring objects for proper mvvm in knockout ) 
Estoy trabajando con Knockout y estoy tratando de mantenernos cierto la estructura MVVM y tratar de hacer que los objetos tengan esa dependencia entre sí. M...

6  Modelo de vista de reloj simple  ( Simple clock view model ) 
He estado tratando de envolver mi cabeza alrededor de MVVM durante la última semana o más y aún luchando un poco. He visto Jason Dolingers MVVM video y ha p...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos