Domanda

Ho implementato un MVP della triade usando la vista modello passivo - vale a dire la vista contiene getter e setter solo semplici. Comunque io sto avendo difficoltà che separa i dati visualizzazione di dati e di modello. In particolare nel trattamento di un cambiamento di stato di visualizzazione.

La triade viene utilizzato per consentire all'utente di selezionare una parte da un elenco. L'elenco dei pezzi è fornita dal modello con ciascuna parte univocamente identificati da un ID univoco.

Diciamo che le parti simile a questa:

class Part
{
    int ID; // this code uniquely identifies the part within the model
    String partCode;
    String description;
    double voltage;
}

la vista visualizza la lista all'utente e permette loro di selezionare una parte

L'elenco viene visualizzato in una DataGridView e una parte viene selezionato cliccando su una riga nella dataGridView.

L'ID non deve essere visualizzato all'utente e non è la tensione, quindi il modello crea un DataTable che contiene solo il partCode e la descrizione. Questo DataTable viene assegnato dal presentatore a una proprietà sulla considerazione che le mappe per la proprietà DataSource DataGridView.

class Presenter
{
    IView _view;
    IModel _model;

    //...///

    _view.Data = _model.GetFilteredData();
}

class Model
{
    public DataTable GetFilteredData()
    {
        // create a DataTable with the partCode and Description columns only
        // return DataTable
    } 
}

class View  //winform
{
      public DataTable Data
      {
          set 
          {
              this.dataGridView.Source = value;
          }
      }
}

Fin qui tutto bene. The View Dislays i dati filtrati nel DataGridView.

Il problema che ho è restituire la parte selezionata dall'utente.

La vista non è a conoscenza della ID univoco in quanto non viene visualizzato e le altre informazioni non può essere garantita per essere unico -. Therfore non è possibile identificare in modo univoco la parte selezionata

Essenzialmente sto cercando di convertire i dati immagine (riga selezionata) ai dati del modello (la parte selezionata) senza un componente usando i dati altri.

Finora ho le seguenti soluzioni:

1) La visualizzazione viene passato un DataTable che contiene l'ID e poi filtra il display in modo che non venga visualizzato all'utente. È allora banale per restituire un ID per la riga selezionata. Il problema è che ho ora inquinato la vista con logica che è testato (il filtraggio del display).

2) La vista restituisce l'indice di riga e il modello corrisponde a questo indice per una riga nei dati originali. Ciò significherebbe garantire che l'ordine nella visualizzazione non cambia mai, che mentre possibile, restringe come la visualizzazione possono mostrare (e manipolare) i dati. Questo inquina anche il modello con dati vista (l'indice di riga).

    public int RowIndexSelected { get; private set; }

    //...//

    private void gridParts_CellEnter(object sender, DataGridViewCellEventArgs e)
    {
        if (SelectedPartChangedEvent != null)
        {
            RowIndexSelected = e.RowIndex;

            SelectedPartChangedEvent();            
        }
    }

3) Una variazione (2). Creare un oggetto adattatore per sedersi tra il presentatore e la vista. Spostare la fila per ID codice di conversione dal modello all'adattatore. Il presentatore gestisce allora l'evento cambiato dataGridAdapters parte.

    public PartSelectDataGridAdapter(IPartSelectView view, PartCollection data)
    {
        _view = view;
        _data = data;

        _view.SelectedPanelChangedEvent += HandleSelectedPartChanged;
    }

    void HandleSelectedPartChanged()
    {
        int id = _data[_view.RowIndexSelected].ID;

        if (SelectedPartChanged != null)
        {
            SelectedPartChanged(id);
        }
    }

Attualmente im apprendimento verso 3 poiché è verificabile, mantiene logica dai dati immagine e vista dal modello e presentatore.

Come si affrontare questo -? C'è una soluzione migliore

È stato utile?

Soluzione

  

L'ID è di non essere visualizzato al   utente e né è la tensione,   quindi il modello crea un   DataTable che contiene solo il   partCode e la descrizione.

Soluzione semplice: do creare una colonna ID nel DataTable e nasconderlo in nella vista datagrid .

Altri suggerimenti

ho postato una soluzione semplice in precedenza; questa è una risposta più dettagliata alla domanda

C'è una ragione per cui non si vuole passare un List<Part> alla vista?

Si potrebbe configurare la griglia per nascondere la colonna id e la tensione. Si può semplicemente ottenere l'oggetto selezionato dalla fonte vincolante nella vista. Il presentatore ha potuto interrogare la vista per questa selezione, o la vista può chiamare un SelectionChanged(Part selected) sul presentatore.

E 'significherebbe che si sta più seguendo rigorosamente la passivo-view modello , ma un < a href = "http://martinfowler.com/eaaDev/SupervisingPresenter.html" rel = "nofollow"> supervisione Controller , perché ora la visualizzazione conosce il modello.

Se non lo fai in questo modo, è possibile introdurre un vista del modello , che fai già implicitamente con il DataTable. (Questo non è necessariamente un male, btw).

Nel tuo esempio, le classi del modello sa sui modelli vista, perché avete metodi sul modello che li generano. Mi piacerebbe consiglio di Inverse questo rapporto: creare metodi sul vostro modello di opinione che dipendono dal vostro oggetti del modello. In questo modo, potrai mantenere il vostro modello classi bello e pulito e indipendente di tutti i dati UI necessarie nel livello di presentazione.

Quando si utilizza la vista del modello / supervisione vie, considerare cadere il concetto DataTable in favore delle classi semplici.

EDIT: un'alternativa per rendere la vista completamente all'oscuro del modello:

Costruire un'istanza di questa classe nel presentatore, in cui si conosce il modello e la vista del modello sia:

public class PartViewModel
{
  object PartModel { get; set; }
  string Name { get; set; }
  string Description { get; set; }
}

Passa un List<PartViewModel> come origine dati per il DataGridView. È possibile restituire l'oggetto PartViewModel selezionato per il presentatore (o usando un evento o utilizzando un metodo). Il presentatore sa che può lanciare la proprietà torna PartModel a un'istanza di parte. La vista non ha bisogno di sapere nulla circa il modello, come dici tu sono preferendo. Ma è ancora possibile utilizzare semplice identità di un oggetto nella presentatore, evitando "complicato" ricerca inversa utilizzando l'id del.

Con un presentatore callback:

interface IPartListPresenter
{
  // other methods
  void SelectedPartChanged(PartViewModel nowSelected);
}

Supponendo partBindingSource è il BindingSource GridView è collegato, è possibile gestire l'evento CurrentChanged di partBindingSource in questo modo:

private void partBindingSource_CurrentChanged(object sender, EventArgs e)
{
  _presenter.SelectedPartChanged(partBindingSource.Current as PartViewModel);
}

Nel presentatore:

public void SelectedPartChanged(PartViewModel nowSelected)
{
  if(nowSelected == null)
  {
    return;
  }
  part myPart = (Part) nowSelected.Part;
  // dos stuff
}

Spero che questo aiuti.

Credo che tu abbia frainteso il concetto un po 'qui!

E 'il presentatore che dovrebbe gestire questa situazione, non il modello. Il modello dovrebbe concentrarsi solo sulla sua esclusiva responsabilità, in caso contrario, si mantiene la vista e modello troppo vicino!

Il mio suggerimento è quello di mantenere una colonna nascosta nella vostra tabella di passare l'evento della riga selezionata al presentatore, e poi lasciare che la maniglia Presenter al lavoro!

Questa sarà l'uso corretto di MVP.

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