Pregunta

He implementado un MVP del Triad con el patrón de vista pasiva - es decir, la vista contiene captadores y definidores solamente simples. Sin embargo estoy teniendo problemas que separa los datos de la vista de datos y modelo. En particular, cuando el manejo de un cambio en el estado de vista.

La tríada se utiliza para permitir al usuario seleccionar una parte de una lista. La lista de partes es suministrada por el modelo con cada parte identificada de manera única por un identificador único.

Digamos que las partes se ven así:

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

La vista muestra la lista al usuario y les permite seleccionar una parte

La lista se muestra en un DataGridView y una parte se selecciona haciendo clic en una fila de la dataGridView.

El ID no debe ser mostrado al usuario y tampoco lo es la tensión, por lo tanto, el modelo crea un DataTable que contiene sólo el partCode y descripción. Este DataTable es asignado por el presentador de una propiedad en la vista que se asigna a la propiedad DataSource del 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;
          }
      }
}

Hasta aquí todo bien. La vista dislays los datos filtrados en el DataGridView.

El problema que tengo es devolver la parte seleccionada por el usuario.

La vista no tiene conocimiento de la identificación única, ya que no aparece y la otra información no puede garantizarse que ser único -. Therfore no es posible identificar de forma exclusiva la parte seleccionada

Básicamente estoy tratando de convertir la vista de datos (la fila seleccionada) a los datos del modelo (la parte seleccionada) y sin un componente utilizando los datos de otros.

Hasta ahora tengo las siguientes soluciones:

1) La vista se pasa una DataTable que contiene el ID y luego filtra la pantalla de manera que no se muestra al usuario. Es entonces trivial para devolver un ID para la fila seleccionada. El problema aquí es que profané ahora la vista con la lógica de que no se ha probado (el filtrado de la pantalla).

2) La vista devuelve el índice de la fila y el modelo coincide con este índice para una fila de los datos originales. Esto significaría asegurar que el orden en la vista nunca cambia, que aunque es posible, restringe la forma en la vista pueden mostrar (y manipular) los datos. Esto también contamina el modelo con vista de datos (el índice de la fila).

    public int RowIndexSelected { get; private set; }

    //...//

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

            SelectedPartChangedEvent();            
        }
    }

3) variación A en (2). Crear un objeto adaptador para sentarse entre el presentador y la vista. Mover la fila de código de conversión de identificación del modelo para el adaptador. El presentador entonces controla el evento cambiado 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);
        }
    }

En la actualidad aprendizaje im hacia 3 ya que es comprobable, mantiene la lógica fuera de la vista y ver los datos de modelo y presentador.

¿Cómo hacer frente a esto? - ¿hay una solución mejor

¿Fue útil?

Solución

El ID se no se mostrará a la de usuario y tampoco lo es la tensión, por lo tanto, crea un modelo DataTable que contiene sólo el partCode y descripción.

Una solución simple: lo crear una columna de ID en la tabla de datos y esconderlo en en la vista de cuadrícula de datos .

Otros consejos

I registró una solución simple anterior; esta es una respuesta más detallada a la pregunta

¿Hay alguna razón usted no desea pasar un List<Part> a la vista?

Se puede configurar la red para ocultar la columna id y el voltaje. Simplemente puede obtener el objeto seleccionado a partir del origen de enlace en la vista. El presentador puede consultar la vista de esta selección, o la vista puede llamar a un SelectionChanged(Part selected) en el presentador.

Esto significaría que ya no está siguiendo estrictamente el href="http://martinfowler.com/eaaDev/PassiveScreen.html" rel="nofollow"> pasivo-vista de un patrón , sino un < a href = "http://martinfowler.com/eaaDev/SupervisingPresenter.html" rel = "nofollow"> supervisar controlador , porque ahora su punto de vista sabe sobre el modelo.

Si no lo hace así, se puede introducir un vista del modelo , que ya lo hacen implícitamente con su DataTable. (Esto no es necesariamente malo, por cierto.)

En el ejemplo, las clases del modelo sabe acerca de los modelos de vista, porque hay métodos en el modelo que los generan. Yo le asesoramiento para invertir esta relación: Crear métodos de su modelo en vista de que dependen de sus objetos del modelo. De esta manera, mantendrá su modelo de clases agradable y limpio e independiente de todos los datos necesarios de interfaz de usuario en la capa de presentación.

Cuando se utiliza la vista del modelo / supervisión de manera controlador, considere la posibilidad de dejar caer el concepto DataTable a favor de las clases simples.

EDIT: alternativa para hacer el punto de vista completamente ignorantes del modelo:

Construir una instancia de esta clase en el presentador, donde se sabe que tanto el modelo y el modelo de vista:

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

Pasar un List<PartViewModel> como una fuente de datos a la DataGridView. Puede devolver el objeto PartViewModel seleccionado para el presentador (ya sea usando un evento o utilizando un método). El presentador sabe que puede emitir la parte trasera propiedad PartModel a una instancia de la Parte. La vista no necesita saber nada sobre el modelo, como usted dice que están prefiriendo. Pero todavía se puede utilizar la identidad del objeto simple en el presentador, evitando "complica" las operaciones de búsqueda utilizando el id de.

Con un presentador de devolución de llamada:

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

Suponiendo partBindingSource es la BindingSource el gridview está conectado a, puede controlar el evento CurrentChanged de partBindingSource como esto:

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

En el presentador:

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

Espero que esto ayude.

Creo que han entendido mal el concepto un poco aquí!

Es el presentador que debe manejar esto, no el modelo. El modelo sólo debe concentrarse en la su propia responsabilidad, si no, se mantiene la vista y modelo demasiado cerca!

Mi sugerencia es mantener una columna oculta en su mesa un pase el caso de la fila seleccionada a su presentador, y luego dejar que el mango Presentador a la obra!

Este será el uso correcto de MVP.

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