Frage

mit MVP, was die normale Reihenfolge der Konstruktion ist und Dependency Injection.

normalerweise erstellen Sie einen Moderator für jede Ansicht und den Blick in den Moderator auf Konstruktor übergeben. Aber was, wenn Sie:

  1. Ein Service, der mehrere Ansichten auf Ereignisse zu hören brauchen auf.
  2. Mehrere Ansichten alle auf den gleichen Datenmodell-Cache zeigt.

kann sich jemand einen normalen Fluss von Informationen von einem Benutzer klicken, um Daten anzuzeigen, aus einem Server in einem Dienst kommen zurück.

War es hilfreich?

Lösung

Hier ist, was ich tue:

Zuerst definiere ich Thesen Schnittstellen:

public interface IView<TPresenter>
{
    TPresenter Presenter { get; set; }
}

public interface IPresenter<TView, TPresenter>
    where TView : IView<TPresenter>
    where TPresenter : IPresenter<TView, TPresenter>
{
    TView View { get; set; }
}

Dann ist diese abstrakte Moderator Klasse:

public abstract class AbstractPresenter<TView, TPresenter> : IPresenter<TView, TPresenter>
    where TView : IView<TPresenter>
    where TPresenter : class, IPresenter<TView, TPresenter>
{
    protected TView view;

    public TView View
    {
        get { return this.view; }
        set
        {
            this.view = value;
            this.view.Presenter = this as TPresenter;
        }
    }
}

Die Ansicht wird über eine Eigenschaft injiziert, statt dem Konstruktor, der bidirektionale Zuneigung in dem Setter zu ermöglichen. Beachten Sie, dass eine sichere Besetzung benötigt wird ...

Dann mein konkreter Moderator ist so etwas wie:

public class MyPresenter : AbstractPresenter<IMyView, MyPresenter>
{
    //...
}

Wo IMyView implementiert IView. Eine konkrete Ansicht Typ muss existiert (z MyView), aber es ist der Container, der es löst:

  1. I registrieren MyPresenter Typ, wie sich in dem Behälter, mit einem Übergangsverhalten.
  2. I registrieren MyView als IMyView in dem Behälter mit einem Übergangsverhalten.
  3. I fragt dann nach einem MyPresenter zum Container.
  4. Container Instanciate ein MyView
  5. Es instanciates eine MyPresenter
  6. Sie den Blick in den Moderator durch die AbstractPresenter.View Eigenschaft injizieren.
  7. Der Setter-Code vervollständigt die bidirektionale Assoziation
  8. Der Container gibt das Paar Moderator / View

Es ermöglicht Ihnen, andere Abhängigkeiten (Dienstleistungen, repos) in beiden Ihre Ansicht und Ihren Moderator zu injizieren. Aber in dem Szenario, das Sie beschrieben, empfehle ich Sie Dienste und Cache-Speicher in den zu injizieren Moderator , anstelle der Ansicht.

Andere Tipps

In WinForms, ziehe ich einen einfachen Ansatz. Normalerweise es zu tun Sie mit ein paar Benutzersteuerelemente auf einer Entwurfsoberfläche - machen diese Ihre Ansicht Klassen. .NET erstellt die Steuerungshierarchie für Sie (via InitializeComponent). Wenn Sie die Passive Ansicht Muster verwenden, jede Ansicht dann instanziiert es Moderators. (Sie können dies entweder direkt oder durch einen IOC-Container zu fragen.) Verwenden Sie Konstruktor Injektion eine Referenz auf die Schnittstelle Sicht passiert an den Konstruktor des Moderatoren. Der Präsentator kann selbst dann verdrahten Ereignisse anzeigen. Wiederholen Sie den Vorgang für das Modell: der Moderator instanziiert ein Modell und Drähte bis zu seinen Veranstaltungen. (In diesem Fall brauchen Sie nicht die Konstruktor Injektion seit Passive Ansicht sagt der Moderator einen Verweis auf das Modell hält, nicht umgekehrt.)

Die einzige nit ich mit diesem Ansatz gefunden haben, ist richtig Lebensdauer des Modells und Moderator zu verwalten. Sie wollen den Blick so einfach wie möglich zu halten, so dass Sie wahrscheinlich nicht wollen, es einen Verweis auf den Vortragenden zu halten. Aber das bedeutet, dass Sie diesen Moderator Objekt haben rumhängen mit Event-Handler zu Ihrer Ansicht gebunden. Diese Einstellung verhindert, dass Ihre Ansicht aus wird Müll gesammelt. Eine Lösung ist, um Ihre Ansicht, die ein Ereignis veröffentlichen, die es zu schließen anzeigt. Der Präsentator würde das Ereignis empfangen und sowohl sein Modell und Ansicht Abonnements entfernen. Die Objekte in Ihrem Web werden nun korrekt dereferenziert und der Garbage Collector über seine Arbeit gehen kann.

Sie winden sich mit etwas wie folgt aus:

public interface IView
{
   ...
   event Action SomeEvent;
   event EventHandler Disposed;
   ...
}

// Note that the IView.Disposed event is implemented by the 
// UserControl.Disposed event. 
public class View : UserControl, IView
{
   public event Action SomeEvent;

   public View()
   {
      var presenter = new Presenter(this);
   }
}

public interface IModel
{
   ...
   event Action ModelChanged;
   ...
}

public class Model : IModel
{
   ...
   public event Action ModelChanged;
   ...
}

public class Presenter
{
   private IView MyView;
   private IModel MyModel;

   public Presenter(View view)
   {
      MyView = view;
      MyView.SomeEvent += RespondToSomeEvent;
      MyView.Disposed += ViewDisposed;

      MyModel = new Model();
      MyModel.ModelChanged += RespondToModelChanged;
   }

   // You could take this a step further by implementing IDisposable on the
   // presenter and having View.Dispose() trigger Presenter.Dispose().
   private void ViewDisposed(object sender, EventArgs e)
   {
      MyView.SomeEvent -= RespondToSomeEvent;
      MyView.Disposed -= ViewDisposed;
      MyView = null;

      MyModel.Modelchanged -= RespondToModelChanged;
      MyModel = null;
   }
}

Sie können dieses Beispiel entkoppeln einen Schritt weiter durch IOC und geben Sie Ihre IOC-Container für Implementierungen von IModel fragen (in der Presenter-Klasse) und IPresenter (in der View-Klasse).

interface IEmployee
{
    int EmployeeId {get;}
    string FirstName {get;}
    string LastName {get;}
}
interface IEmployeeRepository
{
    void SaveEmployee(IEmployee employee);
    IEmployee GetEmployeeById(int employeeId);
    IEmployee[] Employees { get; }
}
interface IEmployeeView
{
    event Action<IEmployee> OnEmployeeSaved;
}

interface IEmployeeController
{
    IEmployeeView View {get;}
    IEmployeeRepository Repository {get;}
    IEmployee[] Employees {get;}        
}

partial class EmployeeView: UserControl, IEmployeeView
{
    public EmployeeView()
    {
        InitComponent();
    }
}
class EmployeeController:IEmployeeController
{
    private IEmployeeView view;
    private IEmployeeRepository repository;
    public EmployeeController(IEmployeeView view, IEmployeeRepository repository)
    {
        this.repository = repository;
        this.view = view;
        this.view.OnEmployeeSaved+=new Action<IEmployee>(view_OnEmployeeSaved);
    }

    void  view_OnEmployeeSaved(IEmployee employee)
    {
        repository.SaveEmployee(employee);
    }
    public IEmployeeView View 
    {
        get
        { 
            return view;
        }
    }
    public IEmployeeRepository Repository
    {
        get
        {
            return repository;
        }
    }

    public IEmployee[] Employees
    {
        get 
        {
            return repository.Employees;
        }
    }
}

WinformsMVP ist ein sehr guter MVP Rahmen für Windows Forms. Sie können ganz einfach einen Service über mehrere Ansichten leicht, diesen Rahmen mit injizieren. Dieses ein guter Artikel ist mit ein Beispiel-Quellcode wird erläutert, wie das Framework verwenden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top