.net - tag - ¿MVVM es inútil?
title en seo (8)
¿La implementación de MVVM ortodoxa es inútil? Estoy creando una nueva aplicación y consideré Windows Forms y WPF. Elegí WPF porque es a prueba de futuro y ofrece mucha flexibilidad. Hay menos código y es más fácil hacer cambios significativos en su UI usando XAML.
Como la elección de WPF es obvia, pensé que también podría utilizar todo el camino utilizando MVVM como arquitectura de aplicaciones, ya que ofrece capacidad de mezcla, problemas de separación y capacidad de prueba de la unidad. Teóricamente, parece hermoso como el santo grial de la programación de UI. Esta breve aventura; sin embargo, se ha convertido en un verdadero dolor de cabeza. Como se esperaba en la práctica, descubro que he cambiado un problema por otro. Tiendo a ser un programador obsesivo porque quiero hacer las cosas de la manera correcta para poder obtener los resultados correctos y posiblemente convertirme en un mejor programador. ¡El patrón de MVVM simplemente suspendió mi prueba de productividad y acaba de convertirse en un hack grande y asqueroso!
El claro ejemplo de esto es agregar soporte para un cuadro de diálogo Modal. La forma correcta es colocar un cuadro de diálogo y vincularlo a un modelo de vista. Hacer esto para trabajar es difícil. Para beneficiarse del patrón MVVM, debe distribuir el código en varios lugares a lo largo de las capas de su aplicación. También debe usar construcciones de programación esotérica como plantillas y expresiones lamba. Cosas que te hacen mirar la pantalla rascándote la cabeza. Esto hace que el mantenimiento y la depuración sean una pesadilla a la espera de que suceda como descubrí recientemente. Tenía una caja de información que funcionaba bien hasta que recibí una excepción la segunda vez que la invoqué, diciendo que no podía volver a mostrar el cuadro de diálogo una vez que se cerró. Tuve que agregar un controlador de eventos para la funcionalidad cercana a la ventana de diálogo, otro en la implementación de IDialogView y finalmente otro en el IDialogViewModel. ¡Pensé que MVVM nos salvaría de tal piratería extravagante!
Hay varias personas con soluciones competitivas para este problema y todas son pirateadas y no ofrecen una solución limpia, fácilmente reutilizable y elegante. La mayoría de los juegos de herramientas de MVVM no tienen en cuenta los diálogos y, cuando los abordan, solo son cuadros de alerta que no requieren interfaces personalizadas ni modelos de visualización.
Planeo abandonar el patrón de vista de MVVM, al menos su implementación ortodoxa. ¿Qué piensas? ¿Te ha valido la pena si tuvieras alguno? ¿Soy simplemente un programador incompetente o MVVM no es lo que se dice que es?
Hacer esto para trabajar es difícil. Para beneficiarse del patrón MVVM, debe distribuir el código en varios lugares a lo largo de las capas de su aplicación. También debe usar construcciones de programación esotérica como plantillas y expresiones lamba.
Para un cuadro de diálogo modal común? Ciertamente está haciendo algo mal allí: la implementación de MVVM no tiene por qué ser tan compleja.
Teniendo en cuenta que es nuevo tanto para MVVM como para WPF, es probable que esté utilizando soluciones que no sean óptimas en todas partes y que complican innecesariamente las cosas, al menos así lo hice cuando entré por primera vez en WPF. Asegúrese de que el problema sea realmente MVVM y no su implementación antes de darse por vencido.
MVVM, MVC, Document-View, etc. es una antigua familia de patrones. Hay inconvenientes, pero no fallas fatales del tipo que describes.
Como el propio patrón MVVM es genial. Pero la biblioteca de control de WPF incluida con soporte de enlace de datos NET 4.0 es muy limitada, es mucho mejor que WinForm, pero aún así no es suficiente para MVVM enlazables, diría que su potencia es de aproximadamente el 30% de lo que se necesita para un MVVM enlazable.
MVVM vinculable: es la interfaz de usuario donde ViewModel está conectado con View solo mediante el enlace de datos.
El patrón MVVM se trata de la representación de objetos de ViewState, no describe cómo se mantiene la sincronización entre View y ViewModel, en WPF es vinculante, pero puede ser cualquier cosa. Y en realidad puedes usar el patrón MVVM en cualquier UI Toolkit, eventos / callbacks de soporte, puedes usarlo en WinAPI puro en WinForms (lo hice, y no es mucho más trabajo con eventos / callbacks), e incluso puedes usarlo en Text Consola, como reescribir Norton Commander de DoS usando un patrón MVVM.
En resumen: MVVM no tiene sentido, es genial. La biblioteca de control de NET 4.0 WPF es basura.
Aquí está la prueba simple del concepto ViewModel, que no se puede enlazar de datos en forma pura MVVM usando WPF.
public class PersonsViewModel
{
public IList<Person> PersonList;
public IList<ColumnDescription> TableColumns;
public IList<Person> SelectedPersons;
public Person ActivePerson;
public ColumnDescription SortedColumn;
}
No se pueden enlazar datos con los encabezados de las columnas DataGrid de WPF, no se pueden vincular las filas seleccionadas, etc., lo hará de forma simple o escribirá 200 líneas de código de piratería XAML para estas 5 líneas de ViewModel más simple. Solo puede imaginarse cómo las cosas se vuelven peores con ViewModels complejos.
Entonces, la respuesta es simple a menos que esté escribiendo la aplicación Hello World, usar MVVM enlazable en WPF no tiene sentido. Pasarás la mayor parte de tu tiempo pensando en hack para vincular ViewModel. El enlace de datos es bueno, pero esté listo para retroceder al 70% de los eventos.
Estoy en medio de un complejo MVVM bastante complejo que usa PRISM, así que ya tuve que lidiar con este tipo de preocupaciones.
Mis conclusiones personales:
MVVM vs MVC / PopUps y co
- MVVM es realmente un gran patrón y en la mayoría de los casos reemplaza completamente a MVC gracias al poderoso enlace de datos en WPF.
- Llamar a su capa de servicio directamente desde el presentador es una implementación legítima en la mayoría de los casos
- Incluso los escenarios bastante complejos de Lista / Detalle pueden implementarse mediante MVVM puro gracias a la sintaxis {Binding Path = /}
- No obstante, cuando se necesita implementar una coordinación compleja entre múltiples puntos de vista, un controlador en
- Los eventos pueden ser usados; el viejo patrón que implica almacenar instancias IView (o AbstractObserver) en el controlador es obsoleto
- El controlador puede ser inyectado en cada presentador por contenedor IOC
- El servicio IEventAggregator de Prism es otra posible solución si el único uso del controlador es el envío de eventos (en este caso, puede reemplazar completamente el controlador)
- Si las vistas se van a crear dinámicamente, este es un trabajo muy adecuado para el controlador (en prisma se inyectará el controlador (IOC) a un IRegionManager)
- Los cuadros de diálogo modales son en su mayoría obsoletos en las aplicaciones compuestas modernas, a excepción de las operaciones realmente bloqueantes como las confirmaciones obligatorias; en estos casos, la activación modal se puede abstraer como un servicio llamado dentro del controlador e implementado por una clase especializada, que también permite pruebas de unidad de nivel de presentación avanzadas. El controlador, por ejemplo, llamará a IConfirmationService.RequestConfirmation ("¿estás seguro?") Que activará una pantalla de diálogo modal en tiempo de ejecución y se puede burlar fácilmente durante las pruebas unitarias
He visto el mismo problema con muchas implementaciones de MVVM cuando se trata de diálogos (modales). Cuando miro a los participantes del Patrón MVVM, tengo la sensación de que falta algo para construir una aplicación coherente.
- La vista contiene los controles de GUI específicos y define la apariencia de la interfaz de usuario.
- ViewModel representa el estado y el comportamiento de la presentación.
- El modelo puede ser un objeto comercial de la capa de dominio o un servicio que proporciona los datos necesarios.
Pero falta es:
- ¿Quién crea los ViewModels?
- ¿Quién es responsable del flujo de trabajo de la aplicación?
- ¿Quién media entre ViewModels cuando necesitan comunicarse entre ellos?
Mi enfoque es introducir un controlador (caso de uso) que sea responsable de los puntos faltantes. Cómo funciona esto se puede ver en las aplicaciones de ejemplo de WPF Application Framework (WAF) .
Lo siento si mi respuesta fue un poco larga, ¡pero no me culpen! Tu pregunta también es larga.
En resumen, MVVM no es inútil.
El claro ejemplo de esto es agregar soporte para un cuadro de diálogo Modal. La forma correcta es colocar un cuadro de diálogo y vincularlo a un modelo de vista. Hacer esto para trabajar es difícil.
Sí, realmente lo es.
Sin embargo, MVVM le proporciona una forma de separar la apariencia de la interfaz de usuario de sus lógicas. Nadie te obliga a usarlo en todas partes, y nadie está sosteniendo un arma contra tu frente para hacerte crear un modelo de vista separado para todo.
Aquí está mi solución para este ejemplo en particular:
Cómo maneja la UI una entrada determinada no es asunto de ViewModel. Agregaría código al archivo .xaml.cs de View, que crea una instancia del cuadro de diálogo y establece la misma instancia de ViewModel (o algo más, si es necesario) como su DataContext.
Para beneficiarse del patrón MVVM, debe distribuir el código en varios lugares a lo largo de las capas de su aplicación. También debe usar construcciones de programación esotérica como plantillas y expresiones lamba.
Bueno, no tienes que usarlo en varios lugares. Así es como lo resolvería:
- Agregue el XAML a la Vista, y nada en .xaml.cs
- Escriba cada lógica de aplicación (excepto las cosas que operarían directamente con elementos de UI) dentro de un ViewModel
- Todo el código que debe ser hecho por la interfaz de usuario, pero que no tiene nada que ver con la lógica de negocios, entra en los archivos .xaml.cs
Creo que el propósito de MVVM es principalmente separar la lógica de la aplicación y la IU concreta, lo que permite modificaciones fáciles (o reemplazo completo) de la IU.
Utilizo el siguiente principio: la Vista puede conocer y asumir cualquier cosa que quiera de ViewModel, pero ViewModel no puede saber NADA sobre la Vista.
WPF proporciona un modelo de enlace agradable que puede usar para lograr exactamente eso.
(Por cierto, las plantillas y expresiones lambda no son esotéricas si se usan correctamente. Pero si no quieres, no las uses).
Cosas que te hacen mirar la pantalla rascándote la cabeza.
Sí, sé la sensación. Exactamente lo que estaba sintiendo cuando vi por primera vez MVVM. Pero una vez que lo domines, ya no se sentirá mal.
Tenía una caja que funcionaba bien ...
¿Por qué pondría un ViewModel detrás de un cuadro de acercamiento? No tiene sentido en eso.
La mayoría de los juegos de herramientas de MVVM no tienen en cuenta los diálogos y, cuando los abordan, solo son cuadros de alerta que no requieren interfaces personalizadas ni modelos de visualización.
Sí, porque el solo hecho de que un elemento de la interfaz de usuario esté en la misma ventana, u otra ventana, o esté en órbita alrededor de Marte en este momento no es una preocupación de ViewModels.
Separación de intereses
EDITAR:
Aquí hay un video muy bonito cuyo título es Build your own MVVM framework . Vale la pena mirar.
Los patrones de diseño están ahí para ayudarlo, no para obstaculizarlo. Una pequeña parte de ser un buen desarrollador es saber cuándo "romper las reglas". Si MVVM es engorroso para una tarea y ha determinado que el valor futuro no vale la pena, entonces no use el patrón. Por ejemplo, como han comentado otros carteles, ¿por qué debería pasar por todos los gastos generales para implementar un cuadro de información simple?
Los patrones de diseño nunca fueron intencionados para ser seguidos dogmáticamente.
Me ocupo del problema de los diálogos haciendo trampa. Mi MainWindow implementa una interfaz IWindowServices que expone todos los cuadros de diálogo específicos de la aplicación. Mis otros ViewModels pueden entonces importar la interfaz de servicios (yo uso MEF, pero podría simplemente pasar la interfaz a través de constructores manualmente) y usarla para lograr lo que sea necesario. Por ejemplo, aquí es cómo se ve la interfaz para una pequeña aplicación de utilidad mía:
//Wrapper interface for dialog functionality to allow for mocking during tests
public interface IWindowServices
{
bool ExecuteNewProject(NewProjectViewModel model);
bool ExecuteImportSymbols(ImportSymbolsViewModel model);
bool ExecuteOpenDialog(OpenFileDialog dialog);
bool ExecuteSaveDialog(SaveFileDialog dialog);
bool ExecuteWarningConfirmation(string text, string caption);
void ExitApplication();
}
Esto pone a todas las ejecuciones de Dialog en un solo lugar y puede apagarse fácilmente para la prueba unitaria. Sigo el patrón que el cliente del diálogo tiene para crear el ViewModel apropiado, que luego pueden configurar según sea necesario. Los bloques de llamadas Ejecutar y luego el cliente pueden mirar los contenidos de ViewModel para ver los resultados del Diálogo.
Un diseño MVVM más "puro" puede ser importante para una aplicación grande, donde necesita un aislamiento más limpio y una composición más compleja, pero para aplicaciones pequeñas y medianas, creo que un enfoque práctico, con los servicios adecuados para exponer los ganchos necesarios, es suficiente .
No, no tiene sentido, pero es difícil entender, aunque el patrón en sí es ridículamente simple. Hay toneladas de desinformación y varios grupos que luchan por el camino correcto. Creo que con WPF y Silverlight deberías usar MVVM o estarás sobrecodificando e intentando resolver problemas en un nuevo modelo, la metodología de formularios "viejos" que te lleva a problemas. Este es el caso más en Silverlight, ya que se requiere que todo sea asincrónico (es posible hacer hackers, pero solo debes elegir otra plataforma).
Sugiero leer este artículo Simplificando el TreeView de WPF usando cuidadosamente el patrón de ViewModel para ver cómo MVVM puede implementarse bien y permitirte cambiar tu mentalidad de formas de ganar a la nueva forma de pensar en MVVM. En resumen, cuando quiera hacer algo, aplique la lógica primero al ViewModel, no a la View. ¿Quieres seleccionar un artículo? Cambiar un icono? No itere sobre los elementos de la interfaz de usuario, simplemente actualice las propiedades de los modelos y permita que el enlace de datos sea esencial.