2010-01-15 10 views
5

Ich habe zwei Möglichkeiten der Initialisierung von Views und ViewModels in WPF CAL MVVM.Was ist die richtige Methode zum Initialisieren eines Modells und einer Ansicht in WPF CAL MVVM

1 - Scheint beliebter zu sein. Erfordert, dass Sie das ViewModel auflösen, um die Ansicht automatisch aufzulösen. Das ViewModel enthält Informationen über die Ansicht.

public interface IView 
    { 
     void SetModel(IViewModel model); 
    } 

    public interface IViewModel 
    { 
     IView View { get; } 
    } 

    public class View 
    { 
     public void SetModel(IViewModel model) 
     { 
      this.DataContext = model; 
     } 
    } 

    public class ViewModel 
    { 
     private IView view; 

     public ViewModel(IView view) 
     { 
      this.view = view; 
     } 

     public IView View { return this.view; } 
    } 

2 - scheint viel sauberer und entfernt den Blick von dem Ansichtsmodell. Erfordert, dass Sie die Ansicht auflösen, um das ViewModel automatisch aufzulösen. Injiziert Objekte in die Ansicht (Nicht sicher, ob dies gut ist oder nicht).

public interface IView 
    { 
    } 

    public interface IViewModel 
    { 
    } 

    public class View 
    { 
     private IViewModel model; 

     public View(IUnityContainer unityContainer) 
     { 
      this.model = unityContainer.Resolve<IViewModel>(); 
      this.DataContext = this.model; 
     } 
    } 

    public class ViewModel 
    { 
    } 

Was ist die akzeptierte Methode der Initialisierung der Ansichten und Modelle und was sind die Vor- und Nachteile der einzelnen Methoden. Sollten Sie Objekte in Ihre Sicht injizieren?

Antwort

3

Sie sind beide gültig, aber # 1 neigt dazu, mehr prüfbar zu sein (es zumindest macht Dich Tests prägnanter). Der Vorteil von # 2 ist, dass es tendenziell expliziter ist und die Wartung ein wenig klarer macht, besonders wenn Sie viel Umsatz haben, so etwas. Nimmt weniger Erklärung (obwohl dies kein Grund ist, es zu übernehmen, es ist nur eine Binsenwahrheit).

Der Unterschied besteht darin, dass # 1 Dependency Injection und # 2 genannt wird, wird Service Lage genannt. Sie sind oft verwirrt, weil beide im Allgemeinen eine Art von IoC-Container verwenden (obwohl dies nicht der Fall sein muss).

Es ist eine Frage der Präferenz am Ende, aber wie gesagt Ich denke, Sie finden # 1 viel einfacher zu testen ... Sie müssen nicht die IUnityContainer-Schnittstelle in Ihre Tests/Mocking einbeziehen.

1

Option 1 sieht richtig aus, geben Sie der Ansicht einen Verweis auf das Viewmodel.

Viewmodels mit einem Verweis zurück zu der Ansicht scheint mir ein bisschen fischig, obwohl. Das sieht mehr wie eine Architektur vom Typ Model-View-Presenter aus. Wenn Sie Ansichtsmodelle haben, die stark mit der Ansicht interagieren und einen Verweis auf die Ansicht benötigen, können Sie das Ansichtsmodell besser in einem Ansichtsmodell aufteilen, das nur für die Datenbindung und einen Moderator verwendet wird, der komplexere Interaktionen durchführt.

Option 2 sieht überhaupt nicht gut aus. Einen Verweis auf den IOC-Container in Klassen zu übergeben, ist ein großer Code-Geruch in meinem Buch. Aufrufe an einen IoC-Container sollten minimiert werden. In den meisten meiner Anwendungen rufe ich nur zu Beginn des Programms in den Container, um die Verbindung aufzubauen. Eine dynamischere Objekterstellung wird normalerweise mit Factory-Klassen durchgeführt.

+0

Die View-Eigenschaft in Option 1 wurde gefunden, von mir in verschiedenen Beispielen, aber ich stimme zu, dass es nicht da sein sollte. – anon

2

Ich ziehe das View-Modell in XAML und bietet eine schreibgeschützte Eigenschaft für typisierten Zugriff zu definieren:

<UserControl ...> 
    <UserControl.DataContext> 
     <local:MyViewModel/> 
    </UserControl.DataContext> 

    ... 

</UserControl> 

public partial class MyView : UserControl, IMyView 
{ 
    public MyViewModel ViewModel 
    { 
     get { return this.DataContext as MyViewModel; } 
    } 

    ... 
} 
+0

+1 für die schreibgeschützte Eigenschaft –

1

Das Problem mit diesem Code ist, dass Option 2 mehr einbrennt, als sie benötigt. Es braucht wirklich keinen Verweis auf den Container und sollte auch keinen haben.

Eine Alternative erlaubt Option 2 so überprüfbar zu sein wie Option 1, aber konzeptionell klarer, weil das ViewModel nie von der Ansicht weiß.

Dies ist besonders nützlich, wenn Sie Ihr Layout mit einer XML-Datei spezifizieren möchten, anstatt die Prismenbereiche zu verwenden, wodurch Sie das Layout leicht konfigurierbar machen können.

Alternative:

public interface IView 
{ 
} 

public interface IViewModel 
{ 
} 

public class View : IView 
{ 
    private IViewModel model; 

    public View(IViewModel m) 
    { 
     this.model = m; 
     this.DataContext = this.model; 
    } 
} 

public class ViewModel : IViewModel 
{ 
} 

und woanders haben:

Container.RegisterType<IViewModel, ViewModel>(/* appropriate container config */); 
Container.RegisterType<IView, View>(/* appropriate container config */); 

und man konnte einen Blick überall mit erstellen:

Container.Resolve<IViewModel>(); 
+0

+1 für die Typauflösung ist nicht die Aufgabe der Ansicht. Ich benutze diesen Ansatz auch und liebe es. – RMart