Domanda

Sto sviluppando un'applicazione WinForms in C #. Ho esperienza limitata nella programmazione GUI, e sto avendo di imparare moltissimo al volo. Detto questo, ecco quello che sto costruendo.

Si veda l'aspetto generale GUI al seguente link:

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

Ora, ho fatto un sacco di lavoro già, ma in pessimo modello di progettazione autonoma. Non sapevo che il progetto avrebbe mai raggiungere una certa dimensione, e, come tale, è il momento di fare un po 'maggiore refactoring.

Ho studiato molto sui modelli di progettazione GUI, e il modello che sto desiderosi di dare attuazione è la vista passivo (vedi http://martinfowler.com/eaaDev/PassiveScreen.html ). Sto cercando qualche aiuto su come portare questo tutti insieme.

Sfondo:

1) A seconda di cosa l'utente fa clic nel "TreeView", la "Lista" nell'angolo in basso a sinistra verrà visualizzato un elenco di oggetti che possono popolano la zona "Editor". Questi oggetti potrebbero essere un TextBox o un DataGridView. L'utente alterna l'elenco per scegliere quello che lui / lei vuole vedere nel "Editor"

2) Il modello è essenzialmente una cartella con i dati ei file di configurazione. C'è un programma esterno che gira su una determinata directory, crea file di output / cartelle, ecc Questo programma sto sviluppando è progettato per gestire in modo efficace / configurare questi oggetti in un modo facile da usare

3) Il problema con il modo in cui ho fatto le cose è che è quasi impossibile di prova, e quindi il passaggio al passivo Visualizza design pattern MVP-esque

che sto cercando di fare in modo che il programma funziona indipendentemente dalla vista. Non sono stato in grado di trovare qualsiasi esempi in cui una più complessa, vista interattivo viene utilizzato con il modello passivo View.

Domande:

1) Ho bisogno di implementare una grande interfaccia / view per l'intero "look" del programma, quindi implementare sub-interfacce / sub-viste per ciascuna delle TreeView, Editor, Logger, ecc? O c'è una migliore "struttura" per fare questo?

2) Quando si tratta di "consegnare a mano" eventi dalla vista al presentatore / Controller (qualunque sia la terminologia che si desidera utilizzare W.R.T. il Passive View disegno del modello), qual è il modo in cui dovrei essere facendo questo? A volte ho semplici proprietà che devono essere aggiornati, e, a volte ho bisogno di tutta una serie di passaggi a svolgersi.

mi piacerebbe suggerimenti e consigli su questo argomento. Ho perlustrato Internet, e non ho trovato esempi adeguati per aiutarmi a continuare con questo progetto.

Grazie in anticipo!

Daniel

È stato utile?

Soluzione

Ecco un semplice esempio che dimostra il concetto di vista passivi che utilizzano il modello di progettazione MVP. Poiché stiamo usando viste passivi la vista non è a conoscenza del presentatore. Il presentatore sarà sufficiente iscriversi agli eventi pubblicati dalla vista e agire di conseguenza.

Per iniziare abbiamo bisogno di definire un contratto per il nostro punto di vista. Ciò si ottiene in genere utilizzando un'interfaccia, sostanzialmente, vogliamo avere un accoppiamento molto sciolto con la nostra vista. Vogliamo che la possibilità di passare a diversi punti di vista o evento creare viste fittizie per test di unità.

Ecco un contratto che descrive una visione semplice che verrà utilizzato per visualizzare le informazioni del cliente

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

Si espone un singolo metodo InitializeCustomers che verrà utilizzato per inizializzare la nostra vista con oggetti del nostro modello.

Abbiamo anche un evento SelectedCustomerChanged che verrà utilizzato dal nostro presentatore di ricevere la notifica che un'azione si è verificata nella vista.

Una volta che abbiamo il nostro contratto possiamo iniziare a gestire queste interazioni nel nostro presentatore.

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);
        }
    }
}

Nel presentatore possiamo usare un altro design pattern chiamato per fornire l'accesso a nostro avviso e tutte le classi di modello che potremmo avere bisogno. In questo esempio ho un CustomerRepository che è responsabile per il recupero dati dei clienti.

Nel costruttore abbiamo due importanti linee di codice, in primo luogo abbiamo sottoscritto l'evento SelectedCustomerChanged a nostro avviso, è qui che siamo in grado di eseguire azioni associate. In secondo luogo abbiamo chiamato InitilaizeCustomers con i dati del repository.

A questo punto non abbiamo in realtà definito una concreta attuazione per il nostro punto di vista, tutto quello che dobbiamo fare è creare un oggetto che implementa ICustomerManagementView . Ad esempio, in un'applicazione Windows Form che possiamo fare le seguenti

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;
}

Se volessimo testare la nostra logica di presentazione abbiamo potuto deridere la nostra visione ed eseguire alcune affermazioni.

EDIT: Incluso args eventi personalizzati

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

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

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

Altri suggerimenti

I li avrebbe abbattere in viste separate con i loro regali, e utilizzare un "controllo" presentatore / visualizzazione per gestire i messaggi di delega tra tutti loro. Non solo questo testabilità aiuto ma manterrò i controlli adempiere SRP, anche.

Quindi nel tuo caso si potrebbe avere un IFormManager che la finestra principale implementerà, e poi un IFileManager, ILoggerWindow ecc ecc.

Anche se potrebbe essere un po 'eccessivo per l'uso, vorrei suggerire che si dispone di uno sguardo a Smart Client Software Factory (da Microsoft Patterns e la squadra Practices) - non è attivamente sviluppato più, ma ha un'implementazione buona di MVP e fa questo genere di cose composizione vista abbastanza bene, quindi potrebbe darvi alcune buone idee.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top