xaml - ejemplo - observablecollection c# example
¿Por qué evitar el código detrás en el patrón WPF MVVM? (4)
En el artículo, Aplicaciones WPF con el patrón de diseño Model-View-ViewModel , el autor que es Josh Smith dijo:
(1) En una arquitectura MVVM bien diseñada, el código detrás de la mayoría de las Vistas debería estar vacío o, como máximo, contener solo código que manipule los controles y recursos contenidos en esa vista. (2) A veces también es necesario escribir código en el código de una Vista detrás que interactúa con un objeto ViewModel, como enganchar un evento o llamar a un método que de otra manera sería muy difícil de invocar desde el ViewModel mismo.
Mi pregunta es, en el (1), por qué el código subyacente vacío se considera como un MVVM bien diseñado. (Parece que el código vacío detrás siempre es bueno).
EDIT: Mi pregunta es, como la siguiente, por qué el enfoque como AttachedCommandBehavior
o InvokeCommandAction
se intenta evitar el código detrás de la codificación.
Déjame explicarte más detalles.
En lo que se refiere al (1), yo pensaría como la siguiente situación a partir de AttachedCommandBehavior . Como Border no implementa ICommandSource
para MouseRightButtonDown
, no puede vincular comúnmente el evento y el ICommand
, pero puede hacerlo con AttachedCommandBehavior .
<!-- I modified some code from the AttachedCommandBehavior to show more simply -->
<Border>
<local:CommandBehaviorCollection.Behaviors>
<local:BehaviorBinding Event="MouseRightButtonDown"
Command="{Binding SomeCommand}"
CommandParameter="A Command on MouseRightButtonDown"/>
</local:CommandBehaviorCollection.Behaviors>
</Border>
O
Podemos hacer esto con System.Windows.Interactivity.InvokeCommandAction
.
<Border xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseRightButtonDown">
<i:InvokeCommandAction Command="{Binding SomeCommand}"
CommandParameter="A Command on MouseRightButtonDown"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Border>
PERO,
Usamos el siguiente XAML y su código Border_MouseRightButtonDown
método Border_MouseRightButtonDown
, que está vinculado al (2) Josh Simth, mencionado anteriormente.
<Border MouseRightButtonDown ="Border_MouseRightButtonDown"/>
Creo que usar codebehind como se muestra arriba no es malo solo porque la diferencia entre estos es solo cuando se vincula un comando o add event handler.
¿Qué piensas sobre esto?
por qué el código subyacente vacío se considera como un MVVM bien diseñado
Tener un archivo de código subyacente que consiste únicamente en una llamada a InitializeComponent () en su constructor significa que ha alcanzado la pureza: no tiene absolutamente ninguna lógica en su código subyacente. No ha contaminado su vista con ningún código que pertenezca legítimamente en el modelo de vista o modelo. Esto significa un par de cosas:
- el modelo de vista (y el modelo) es más fácil de probar en forma aislada
- ha logrado un buen nivel de acoplamiento flexible, que tiene excelentes beneficios desde una perspectiva de mantenimiento y extensibilidad
Los beneficios realmente se notan cuando tienes que cambiar tu UI, es decir, pasas de usar ListView a DataGrid, o cambias de usar los controles estándar de Microsoft a usar otros proveedores.
Como se mencionó, a veces es imposible evitar un pequeño código en el archivo de código subyacente. Lo que debes asegurarte es que el código que tienes está relacionado puramente con la interfaz de usuario. Como ejemplo, si tiene ComboA y ComboB, y ComboB se configura en respuesta a la selección en ComboA, entonces establecer el SelectedIndex de ComboB desde la vista está bien, pero establecer los Items o el SelectedItem de ComboB no es - esas propiedades son ambos datos relacionados y deben especificarse vinculando al modelo de vista. La propiedad SelectedIndex está directamente relacionada con la vista y es algo independiente de los datos reales (y es irrelevante para el modelo de vista).
Si accede al modelo de vista desde el código subyacente en la vista, intente hacerlo a través de una interfaz. Esto significa que su modelo de vista se inyecta o se le da a la vista como una interfaz. (Tenga en cuenta que el subsistema de enlace no conoce o no le importa la interfaz, continuará uniéndose de la manera normal. Lo que esto logra es un mejor código, con un acoplamiento menos ajustado). La forma en que lo codigo, el modelo de vista no tiene idea de que existe una vista, y la vista solo sabe sobre el modelo de vista como una interfaz.
Sin embargo, una cosa para recordar es que MVVM es un patrón, y un patrón es simplemente una receta o prescripción para lograr un determinado resultado en una determinada situación. No debe tratarse como una religión, donde los no creyentes o los inconformistas van a ir a algún purgatorio (aunque la adhesión al patrón es buena si se quiere evitar el purgatorio del infierno de mantenimiento y el olor del código ).
Si desea un excelente ejemplo de cómo este patrón en particular ayuda, intente escribir algunas pantallas razonablemente complicadas en ASP.Net, y luego escriba lo mismo en WPF o Silverlight, y observe la diferencia.
Editar:
déjame responder algunas de tus preguntas, espero que ayude ...
El rol de viewmodel (modelo de vista), en mi opinión, tiene lógica de UI y estado de una vista
El modelo de vista nunca debe tener ninguna lógica de UI o "estado de vista" en él. A los efectos de esta explicación, definiría el estado de la vista como posición de desplazamiento, índice de fila seleccionado, índice seleccionado, tamaño de ventana, etc. Ninguno de ellos pertenece al modelo de vista; cosas como SelectedIndex son específicas de la forma en que se muestran los datos en la UI (si cambia el orden de clasificación de un DataGrid, entonces el SelectedIndex puede cambiar, aunque el SelectedItem siga siendo el mismo). En este caso particular, el elemento seleccionado se puede vincular al modelo de vista, pero el índice seleccionado no.
Si necesita realizar un seguimiento de la sesión de UI, escriba información de ellos, entonces debe encontrar algo genérico (por ejemplo, he conservado estado de vista antes guardando cosas importantes en una lista de KeyValuePair) que luego se "guarda" con una llamada al viewmodel (a través de la interfaz que mencioné anteriormente). La vista no tiene idea de cómo se están guardando los datos, y el modelo de vista no tiene idea de que los datos provienen de una vista (simplemente ha expuesto una llamada a través de su interfaz).
y el rol de la vista es mostrar algunos contenidos y sincronizar el modelo de vista (que tiene un código de enlace de datos)
Sí, la responsabilidad de la vista es simplemente mostrar visualmente los datos presentados por el modelo de vista. El modelo de vista obtiene los datos del modelo (el modelo es responsable de hacer llamadas a la base de datos o llamadas al servicio web WCF, esto generalmente se hará a través de un "servicio", pero eso es un debate completamente diferente). El modelo de vista puede entonces dar forma o manipular los datos, es decir, puede obtener una lista de todos los clientes, pero solo expone una versión filtrada de esa lista (tal vez los clientes actuales) en una propiedad pública a la que la vista se puede vincular.
Si los datos se van a manipular en algo visual (un ejemplo común es un valor enum que se traduce en un color), el modelo de vista solo tiene el valor enum (s), y la vista aún se enlaza a ese valor, pero la vista también usa un convertidor para traducir los datos puros a una representación visual. Al usar el convertidor, el modelo de vista todavía ha evitado hacer algo relacionado con la interfaz de usuario, y la vista ha evitado cualquier lógica real.
Creo que la sección citada se refiere a la forma en que se visualizan los datos. Creo que significan que no debe escribir código en el código que está, por ejemplo, relacionado con cómo o dónde se muestran los datos (por ejemplo algo así como: label1.Text = ...
). Hacer cosas como esas utilizando enlaces hace que sea más fácil separar el diseño y el código (¿qué sucede si necesita que los datos se muestren en un cuadro de texto llamado "tbTest" en una versión posterior? Tendría que cambiar su código).
No dicen que no debas tener ningún código en el código: solo dicen que en un mundo ideal, solo reaccionarías ante eventos o procesarías datos que de otro modo no podrían procesarse.
Al menos eso es lo que entiendo de la sección que citó.
El MVVM puede dividir código y diseño de página por completo; los codificadores solo se preocupan por la codificación y los diseñadores solo se preocupan por el diseño. Pero:
- Nunca he visto a ningún diseñador que use Blend o comprendo XAML.
- Casi todos los XAML están escritos por el propio codificador.
No hay nada intrínsecamente malo en el código subyacente. Para casos simples, está bien tenerlo. Sin embargo, la lógica de la interfaz de usuario puede ser difícil de gestionar en muchos escenarios. Encapsular esa lógica en comportamientos adjuntos y modelos de vista nos permite aislar las variables (y probarlas) para que sea más fácil de comprender y mantener.
Si la capacidad de prueba es una preocupación, cuanto mayor sea su lógica de UI que pueda encapsular en modelos de vista y comportamientos adjuntos, más podrá verificar sin recurrir a pruebas de UI. (Si bien no elimina por completo la necesidad de pruebas de UI, proporciona un primer nivel de verificación antes de participar en las pruebas de UI, lo que requerirá más tiempo y recursos.