visual vista studio mvc modelo form controlador c# design-patterns mvp passive-view

studio - C#WinForms Model-View-Presenter(Vista pasiva)



mvc c# windows forms (2)

Aquí hay un ejemplo simple que demuestra el concepto de vistas pasivas usando el patrón de diseño MVP. Debido a que estamos utilizando vistas pasivas, la vista no tiene conocimiento del presentador. El presentador simplemente se suscribirá a los eventos publicados por la vista y actuará en consecuencia.

Para empezar necesitamos definir un contrato para nuestra vista. Esto se logra normalmente utilizando una interfaz, esencialmente, queremos tener un acoplamiento muy suelto con nuestra vista. Queremos la posibilidad de cambiar a diferentes vistas o crear vistas simuladas de eventos para pruebas de unidad.

Aquí hay un contrato que describe una vista simple que se usará para mostrar la información del cliente

public interface ICustomerManagementView { void InitializeCustomers(ICustomer[] customers); void DisplayCustomer(ICustomer customer); event EventHandler<EventArgs<ICustomer>> SelectedCustomerChanged; }

Expone un solo método InitializeCustomers que se utilizará para inicializar nuestra vista con objetos de nuestro modelo.

También tenemos un evento SelectedCustomerChanged que será utilizado por nuestro presentador para recibir una notificación de que se ha producido una acción en la vista.

Una vez que tengamos nuestro contrato, podemos comenzar a manejar estas interacciones en nuestro presentador.

public class CustomerManagementPresenter { private ICustomer _selectedCustomer; private readonly ICustomerManagementView _managementView; private readonly ICustomerRepository _customerRepository; public CustomerManagementPresenter(ICustomerManagementView managementView, ICustomerRepository customerRepository) { _managementView = managementView; _managementView.SelectedCustomerChanged += this.SelectedCustomerChanged; _customerRepository = customerRepository; _managementView.InitializeCustomers(_customerRepository.FetchCustomers()); } private void SelectedCustomerChanged(object sender, EventArgs<ICustomer> args) { // Perform some logic here to update the view if(_selectedCustomer != args.Value) { _selectedCustomer = args.Value; _managementView.DisplayCustomer(_selectedCustomer); } } }

En el presentador podemos usar otro patrón de diseño llamado inyección de dependencia para proporcionar acceso a nuestra vista y cualquier clase de modelo que podamos necesitar. En este ejemplo, tengo un CustomerRepository que se encarga de obtener los detalles del cliente.

En el constructor tenemos dos líneas de código importantes, en primer lugar nos hemos suscrito al evento SelectedCustomerChanged en nuestra vista, es aquí donde podemos realizar las acciones asociadas. En segundo lugar, hemos llamado a InitilaizeCustomers con datos del repositorio.

En este punto, en realidad no hemos definido una implementación concreta para nuestra vista, todo lo que necesitamos hacer es crear un objeto que implemente ICustomerManagementView . Por ejemplo, en una aplicación de Windows Forms podemos hacer lo siguiente

public partial class CustomerManagementView : Form, ICustomerManagementView { public CustomerManagementView() { this.InitializeComponents(); } public void InitializeCustomers(ICustomer[] customers) { // Populate the tree view with customer details } public void DisplayCustomer(ICustomer customer) { // Display the customer... } // Event handler that responds to node selection private void CustomerTreeViewAfterSelect(object sender, TreeViewEventArgs e) { var customer = e.Node.Tag as ICustomer; if(customer != null) { this.OnSelectedCustomerChanged(new EventArgs<ICustomer>(customer)); } } // Protected method so that we can raise our event protected virtual void OnSelectedCustomerChanged(EventArgs<ICustomer> args) { var eventHandler = this.SelectedCustomerChanged; if(eventHandler != null) { eventHandler.Invoke(this, args); } } // Our view will raise an event each time the selected customer changes public event EventHandler<EventArgs<ICustomer>> SelectedCustomerChanged; }

Si quisiéramos probar nuestra lógica de presentación, podríamos burlarnos de nuestra vista y realizar algunas afirmaciones.

EDITAR: Incluye eventos personalizados args

public class EventArgs<T> : EventArgs { private readonly T _value; public EventArgs(T value) { _value = value; } public T Value { get { return _value; } } }

Estoy desarrollando una aplicación WinForms en C #. Tengo experiencia limitada en la programación de GUI, y tengo que aprender mucho sobre la marcha. Dicho esto, esto es lo que estoy construyendo.

Vea el GUI general en el siguiente enlace:

GUI http://img227.imageshack.us/img227/1084/program0.jpg

Ahora, ya he hecho un montón de trabajo, pero en el muy mal patrón de diseño autónomo. No sabía que el proyecto alcanzaría un cierto tamaño y, como tal, es hora de hacer una importante refactorización.

He estado estudiando mucho sobre los patrones de diseño de GUI, y el patrón que deseo implementar es la vista pasiva (consulte http://martinfowler.com/eaaDev/PassiveScreen.html ). Estoy buscando ayuda sobre cómo reunir todo esto.

Fondo:

1) Dependiendo de lo que el usuario haga clic en "TreeView", la "Lista" en la esquina inferior izquierda mostrará una lista de objetos que pueden llenar el área "Editor". Estos objetos pueden ser un TextBox o un DataGridView. El usuario alterna la Lista para elegir lo que desea ver en el "Editor"

2) El modelo es esencialmente una carpeta con datos y archivos de configuración. Hay un programa externo que se ejecuta en un directorio determinado, crea archivos / carpetas de salida, etc. Este programa que estoy desarrollando está diseñado para administrar / configurar estos objetos de manera fácil y sencilla.

3) El problema con la forma en que he estado haciendo las cosas es que es casi imposible de probar y, por lo tanto, el cambio al patrón de diseño de vista pasiva de MVP esque

Estoy tratando de hacerlo para que el programa funcione independientemente de la Vista. No he podido encontrar ningún ejemplo donde se use una vista interactiva más compleja con el patrón de vista pasiva.

Preguntas:

1) ¿Debo implementar una interfaz / vista grande para el "aspecto" completo del programa, luego implementar sub-interfaces / sub-vistas para cada uno de los TreeView, Editor, Logger, etc.? ¿O hay una mejor "estructura" para hacer esto?

2) Cuando se trata de "pasar" los eventos de la Vista al Presentador / Controlador (independientemente de la terminología que desee utilizar con el patrón de diseño de la Vista Pasiva de WRT), ¿cuál es la forma en que debería hacerlo? A veces tengo propiedades simples que necesitan actualizarse, y otras veces necesito toda una serie de pasos para desarrollarme.

Me encantaría sugerencias y consejos sobre este tema. He rastreado Internet y no he encontrado ejemplos adecuados para ayudarme a continuar con este proyecto.

¡Gracias por adelantado!

Daniel


Los dividiría en vistas separadas con sus propios regalos y utilizaría un presentador / vista "controlador" para administrar la delegación de mensajes entre todos ellos. Esto no solo ayudará a la capacidad de prueba, sino que también mantendrá sus controles cumpliendo el SRP.

Entonces, en su caso, podría tener un IFormManager que implementará su ventana principal, y luego un IFileManager, ILoggerWindow, etc.

Aunque podría ser un poco excesivo de usar, sugeriría que eche un vistazo a Smart Client Software Factory (del equipo de Patrones y Prácticas de Microsoft). Ya no se está desarrollando activamente, pero tiene una buena implementación de MVP y este tipo de vista de la composición es bastante buena, por lo que podría darle algunas buenas ideas.