Question

Je l'ai mis en place un MVP triade en utilisant le modèle de vue passif - à savoir la vue ne contient que accesseurs simples et setters. Cependant, je ne parviens pas à les données seperating et des données modèle vue. En particulier lors de la manipulation d'un changement dans l'état d'affichage.

La triade est utilisée pour permettre à l'utilisateur de sélectionner une partie à partir d'une liste. La liste des pièces est fournie par le modèle avec chaque partie identifiée de manière unique par un identifiant unique.

Permet de dire que les parties ressemblent à ceci:

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

La vue affiche la liste à l'utilisateur et leur permet de sélectionner une partie

La liste est affichée dans un DataGridView et une partie est sélectionnée en cliquant sur une ligne dans la datagridview.

L'ID est de ne pas être affiché à l'utilisateur et n'est la tension, donc le modèle crée un DataTable qui contient juste la partCode et la description. Ce DataTable est attribué par le présentateur à une propriété sur la vue que les cartes à la propriété DataSource du 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;
          }
      }
}

Jusqu'à présent, si bon. La vue dislays les données filtrées dans le DataGridView.

Le problème que j'ai revient la partie sélectionnée par l'utilisateur.

Le point de vue n'a pas connaissance de l'identifiant unique car il n'est pas affiché et l'autre information ne peut être garantie unique -. Therfore il est impossible d'identifier de manière unique la partie sélectionnée

Pour l'essentiel, je suis en train de convertir des données d'affichage (la ligne sélectionnée) aux données du modèle (la partie sélectionnée) sans un composant à l'aide des données autres.

Jusqu'à présent, j'ai les solutions suivantes:

1) La vue est passé un DataTable qui contient l'ID et filtre alors l'affichage pour qu'il ne soit pas affiché à l'utilisateur. Il est alors trivial de retourner une carte d'identité pour la ligne sélectionnée. Le problème ici est que je l'ai maintenant pollué la vue avec la logique qui est non testé (le filtrage de l'écran).

2) L'affichage retourne l'index de ligne et le modèle correspondant à cet indice à une ligne dans les données d'origine. Cela signifie veiller à ce que l'ordre dans la vue ne change jamais, qui, tout possible, comment la vue restreint peuvent montrer (et manipuler) les données. Cela pollue également le modèle avec des données de vue (l'indice de ligne).

    public int RowIndexSelected { get; private set; }

    //...//

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

            SelectedPartChangedEvent();            
        }
    }

3) Une variante (2). Créer un objet adaptateur pour s'asseoir entre le présentateur et la vue. Déplacer la ligne de code de conversion ID du modèle à l'adaptateur. Le présentateur gère alors la partie de dataGridAdapters événement changé.

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

À l'heure actuelle l'apprentissage des im vers 3 car il est testable, maintient la logique à partir des données de vue et vue sur le modèle et le présentateur.

Comment voulez-vous aborder ce - est-il une meilleure solution

Était-ce utile?

La solution

  

L'ID est de ne pas être affiché à la   utilisateur et ni est la tension,   Par conséquent, le modèle crée une   DataTable qui contient juste la   partCode et description.

Solution simple: faire créer une colonne d'identité dans le datatable et cacher dans la vue DataGrid .

Autres conseils

J'ai posté une solution simple plus tôt; c'est une réponse plus détaillée à la question

Y at-il une raison que vous ne voulez pas passer un List<Part> à la vue?

vous pouvez configurer la grille pour masquer l'identifiant et la colonne tension. Vous pouvez simplement obtenir l'objet sélectionné à partir de la source de liaison dans la vue. Le présentateur pourrait interroger la vue pour cette sélection, ou la vue peut appeler un SelectionChanged(Part selected) sur le présentateur.

Il voudrait dire que vous n'êtes plus strictement suivant le modèle -vue passif , mais < a href = "http://martinfowler.com/eaaDev/SupervisingPresenter.html" rel = "nofollow"> supervision contrôleur, parce que maintenant votre point de vue sur le modèle connaît.

Si vous ne le faites pas comme cela, vous pouvez introduire un modèle de vue , que vous faites déjà implicitement avec votre DataTable. (Ce n'est pas nécessairement mauvais, btw.)

Dans votre exemple, les classes de modèle connaît les modèles de vue, parce que vous avez des méthodes sur le modèle qui les génèrent. Je vous conseille d'inverser cette relation: créer des méthodes sur votre modèle de vue qui dépendent de vos objets de modèle. De cette façon, vous garderez votre cours modèle agréable et propre et indépendant de toutes les données nécessaires de l'interface utilisateur dans la couche de présentation.

Lorsque vous utilisez le mode modèle de vue / contrôleur de supervision, envisager de laisser tomber le concept DataTable en faveur des classes simples.

EDIT: alternative pour faire le point de vue complètement ignorant du modèle:

Construire une instance de cette classe dans le présentateur, où vous connaissez le modèle à la fois modèle et vue:

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

Passez un List<PartViewModel> comme source de données à la DataGridView. Vous pouvez renvoyer l'objet PartViewModel sélectionné pour le présentateur (soit en utilisant un événement ou en utilisant une méthode). Le présentateur sait qu'il peut jeter l'arrière de la propriété PartModel à une instance partie. La vue n'a pas besoin de savoir quoi que ce soit sur le modèle, comme vous le dites vous Préférer. Mais vous pouvez toujours utiliser une simple identité d'objet dans le présentateur, en évitant « compliqué » id rechercher à l'aide de.

Avec un rappel présentateur:

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

En supposant partBindingSource est BindingSource le gridview est connecté, vous pouvez gérer l'événement CurrentChanged de partBindingSource comme ceci:

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

Dans le présentateur:

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

Hope this helps.

Je pense que vous avez mal compris le concept un peu ici!

Il est le présentateur qui doit gérer cela, pas le modèle. Le modèle ne doit se concentrer sur la sa seule responsabilité, sinon, vous gardez la vue et le modèle trop près!

Ma suggestion est de garder une colonne cachée dans votre table un passer l'événement de la ligne sélectionnée à votre présentateur, puis laisser la poignée Presenter au travail!

Ce sera l'utilisation correcte de MVP.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top