Questa è la mia modesta interpretazione di MVP e dei tuoi problemi specifici.
In primo luogo , tutto ciò con cui un utente può interagire, o semplicemente essere mostrato, è una vista . Le leggi, il comportamento e le caratteristiche di tale vista sono descritti da un'interfaccia . Quell'interfaccia può essere implementata utilizzando un'interfaccia utente WinForms, un'interfaccia utente console, un'interfaccia utente web o addirittura nessuna interfaccia utente (di solito quando si testa un presentatore): l'implementazione concreta non ha importanza fintanto che obbedisce alle leggi della sua interfaccia di visualizzazione .
In secondo luogo , una visualizzazione è sempre controllata da un presentatore . Le leggi, il comportamento e le caratteristiche di un tale presentatore sono descritti anche da un'interfaccia . Quell'interfaccia non ha alcun interesse nell'implementazione della vista concreta fintanto che obbedisce alle leggi della sua interfaccia di visualizzazione.
Terzo , dal momento che un presentatore controlla la propria visualizzazione, per ridurre al minimo le dipendenze non c'è davvero alcun vantaggio nel fatto che la visualizzazione sappia qualcosa sul suo presentatore. Esiste un contratto concordato tra il presentatore e la vista e questo viene dichiarato dall'interfaccia della vista.
Le implicazioni di Third sono:
- Il presentatore non dispone di metodi che la visualizzazione può chiamare, ma la visualizzazione ha eventi a cui il presentatore può iscriversi.
- Il presentatore conosce il suo punto di vista. Preferisco farlo con l'iniezione del costruttore sul presentatore concreto.
- La vista non ha idea di quale presentatore la stia controllando; non verrà mai fornito alcun presentatore.
Per il tuo problema, quanto sopra potrebbe apparire così in un codice un po 'semplificato:
interface IConfigurationView
{
event EventHandler SelectConfigurationFile;
void SetConfigurationFile(string fullPath);
void Show();
}
class ConfigurationView : IConfigurationView
{
Form form;
Button selectConfigurationFileButton;
Label fullPathLabel;
public event EventHandler SelectConfigurationFile;
public ConfigurationView()
{
this.selectConfigurationFileButton.Click += delegate
{
var Handler = this.SelectConfigurationFile;
if (Handler != null)
{
Handler(this, EventArgs.Empty);
}
};
}
public void SetConfigurationFile(string fullPath)
{
this.fullPathLabel.Text = fullPath;
}
public void Show()
{
this.form.ShowDialog();
}
}
interface IConfigurationPresenter
{
void ShowView();
}
class ConfigurationPresenter : IConfigurationPresenter
{
Configuration configuration = new Configuration();
IConfigurationView view;
public ConfigurationPresenter(IConfigurationView view)
{
this.view = view;
this.view.SelectConfigurationFile += delegate
{
var selectFilePresenter = Gimme.The<ISelectFilePresenter>();
selectFilePresenter.ShowView();
this.configuration.FullPath = selectFilePresenter.FullPath;
this.view.SetConfigurationFile(this.configuration.FullPath);
};
}
public void ShowView()
{
this.view.SetConfigurationFile(this.configuration.FullPath);
this.view.Show();
}
}
Oltre a quanto sopra, di solito ho un'interfaccia di base in IView
cui ripongo la Show()
vista o il titolo della vista di qualsiasi proprietario di cui generalmente beneficiano le mie visualizzazioni.
Alle tue domande:
1. Quando il winform viene caricato, deve ottenere una visualizzazione ad albero. Ho ragione nel pensare che la vista dovrebbe quindi chiamare un metodo come: presenter.gettree (), questo a sua volta delegherà al modello, che otterrà i dati per la treeview, lo creerà e lo configurerà, lo restituirà al presenter, che a sua volta passerà alla visualizzazione che poi lo assegnerà semplicemente, diciamo, a un pannello?
Chiamerei IConfigurationView.SetTreeData(...)
da IConfigurationPresenter.ShowView()
, subito prima della chiamata aIConfigurationView.Show()
2. Sarebbe lo stesso per qualsiasi controllo dati su Winform, dato che ho anche un datagridview?
Sì, lo chiamerei IConfigurationView.SetTableData(...)
. Sta alla vista formattare i dati forniti. Il presentatore obbedisce semplicemente al contratto della vista che vuole dati tabulari.
3. My App, ha un numero di classi di modelli con lo stesso assembly. Supporta anche un'architettura plug-in con plug-in che devono essere caricati all'avvio. La vista chiamerebbe semplicemente un metodo del presentatore, che a sua volta chiamerebbe un metodo che carica i plugin e mostra le informazioni nella vista? Quale livello controllerebbe quindi i riferimenti del plug-in. La visualizzazione conterrebbe riferimenti a loro o al presentatore?
Se i plugin sono relativi alla visualizzazione, le visualizzazioni dovrebbero conoscerli, ma non il presentatore. Se riguardano solo dati e modelli, la vista non dovrebbe avere nulla a che fare con essi.
4. Ho ragione nel pensare che la vista dovrebbe gestire ogni singola cosa sulla presentazione, dal colore del nodo treeview, alla dimensione del datagrid, ecc.?
Sì. Consideralo come il presentatore che fornisce XML che descrive i dati e la vista che prende i dati e applica ad essi un foglio di stile CSS. In termini concreti, il presentatore potrebbe chiamare IRoadMapView.SetRoadCondition(RoadCondition.Slippery)
e la vista quindi rappresenterà la strada in colore rosso.
E i dati per i nodi cliccati?
5. Se quando clicco sui treenodes, dovrei passare attraverso il nodo specifico al presenter e quindi da quello il presenter elaborerà i dati di cui ha bisogno e poi chiederà al modello quei dati, prima di presentarli di nuovo alla vista?
Se possibile, passerei tutti i dati necessari per presentare l'albero in una vista in un colpo solo. Ma se alcuni dati sono troppo grandi per essere passati dall'inizio o se sono di natura dinamica e richiedono l '"ultima istantanea" dal modello (tramite il presentatore), aggiungerei qualcosa di simile event LoadNodeDetailsEventHandler LoadNodeDetails
all'interfaccia di visualizzazione, in modo che il il presentatore può iscriversi ad esso, recuperare i dettagli del nodo in LoadNodeDetailsEventArgs.Node
(possibilmente tramite il suo ID di qualche tipo) dal modello, in modo che la vista possa aggiornare i dettagli del nodo visualizzati quando il delegato del gestore di eventi ritorna. Tieni presente che potrebbero essere necessari modelli asincroni di questo tipo se il recupero dei dati potrebbe essere troppo lento per una buona esperienza utente.