Pregunta

Estoy desarrollando una aplicación de Windows Forms en C #. Tengo poca experiencia en programación de interfaz gráfica de usuario, y estoy teniendo que aprender mucho sobre la marcha. Una vez dicho esto, esto es lo que estoy construyendo.

Vea el aspecto general de interfaz gráfica de usuario en el siguiente enlace:

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

Ahora, he hecho un montón de trabajo ya, pero en el patrón de diseño muy mala Autónoma. No sabía que el proyecto nunca llegar a un cierto tamaño, y, como tal, es el momento de hacer algo de refactorización importante.

He estudiado mucho acerca de los patrones de diseño GUI, y el patrón Estoy deseando poner en práctica es la vista pasivo (ver http://martinfowler.com/eaaDev/PassiveScreen.html ). Busco algo de ayuda sobre cómo llevar esto todo juntos.

Antecedentes:

1) En función de lo que el usuario hace clic en el "TreeView", la "Lista" en la esquina inferior izquierda se mostrará una lista de objetos que pueden poblar la zona "Editor". Estos objetos pueden ser un cuadro de texto o una DataGridView. El usuario cambia la lista para elegir lo que él / ella quiere ver en el "Editor"

2) El modelo es esencialmente una carpeta con los datos y archivos de configuración. Existe un programa externo que se ejecuta en un directorio dado, crea archivos de salida / carpetas, etc. Este programa que estoy desarrollando está diseñado para gestionar con eficacia / configure estos objetos en una forma fácil de usar

3) El problema con la forma en que he estado haciendo las cosas es que es casi imposible de prueba, y por lo tanto el paso a la pasiva Vista patrón de diseño MVP-esque

Estoy tratando de hacerlo de modo que el programa funciona de forma independiente de la Vista. No he podido encontrar ningún ejemplo donde un más complejo, vista interactiva se utiliza con el patrón Passive View.

Preguntas:

1) ¿Es necesario poner en práctica una amplia interfaz / vista para toda la "mirada" del programa, a continuación, aplicar sub-interfaces / sub-puntos de vista de cada uno de los TreeView, Editor, maderero, etc.? ¿O hay una "estructura" mejor hacer esto?

2) Cuando se trata de "dar el relevo" eventos desde la vista a la / Controlador Presentador (cualquiera que sea la terminología que desea utilizar w.r.t. el patrón de diseño pasivo Vista), lo que es la forma en que debería estar haciendo esto? A veces tengo propiedades simples que necesitan ser actualizados, ya veces necesito toda una serie de medidas para desarrollarse.

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

Gracias de antemano!

Daniel

¿Fue útil?

Solución

Este es un ejemplo sencillo que muestra el concepto de puntos de vista pasivos utilizando el patrón de diseño MVP. Debido a que estamos usando vistas pasivos de la vista no tiene conocimiento de que el presentador. El presentador simplemente suscribirse a eventos publicados por la vista y actuar en consecuencia.

Para empezar, tenemos que definir un contrato para nuestra opinión. Esto se logra típicamente usando una interfaz, en esencia, queremos tener un acoplamiento muy floja con nuestra opinión. Queremos que la capacidad de cambiar a diferentes puntos de vista o evento de crear vistas simuladas para pruebas unitarias.

Aquí es un contrato que describe una visión simple que se utiliza para información de visualización del cliente

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

Se expone un método único InitializeCustomers que será utilizado para inicializar nuestro punto de vista con los objetos de nuestro modelo.

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

Una vez que tenemos nuestro contrato podemos empezar 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 utilizar otro patrón de diseño llamado inyección de dependencias para proporcionar acceso a nuestro punto de vista y las clases de modelo que puedan necesitar. En este ejemplo tengo un CustomerRepository que se encarga de ir a buscar los datos del cliente.

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

En este punto no hemos definido en realidad una aplicación concreta para nuestro punto de vista, todo lo que tenemos que hacer es crear un objeto que implementa ICustomerManagementView . Por ejemplo, en una aplicación de Windows Forms que 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 poner a prueba nuestra lógica de presentación podríamos burlarse de nuestro punto de vista y realizar algunas afirmaciones.

EDIT: Incluido argumentos de eventos personalizados

public class EventArgs<T> : EventArgs
{
    private readonly T _value;

    public EventArgs(T value)
    {
        _value = value;
    }

    public T Value
    {
        get { return _value; }
    }
}

Otros consejos

Me descomponerlas en vistas separadas con sus propios regalos, y utilizar un "control" presentador / vista para gestionar la delegación de mensajes entre todos ellos. Esto no sólo la capacidad de prueba ayuda, sino que va a mantener los controles de cumplimiento de SRP, también.

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

A pesar de que podría ser un poco exagerado para su uso, sugeriría que usted tiene un vistazo a Smart Client Software Factory (a partir de los patrones de Microsoft y el equipo de Prácticas) - no está siendo desarrollado activamente más, pero tiene una aplicación buena de MVP y lo hace este tipo de vista composición cosas bastante bien, por lo que podría darle algunas ideas buenas.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top