Frage

Ich habe ein sehr großes LOB App mit meinem Geschmack von M-V-VM entwickelt, die ich M-V-MC (Model-View-ModelController) nennen, die zwischen M-V-C und M-V-VM eine Art Kombination ist. Ich hatte geschrieben diese Antwort in Bezug auf wie Ansichten in MV-VM auf die Frage instanziiert erhalten „ was-ist-das-meist-common-Fehler-made-in-wpf-Entwicklung “.

Sam machte folgenden Kommentar in Bezug auf meine Antwort:

  

Dies schafft eine Follow-up-Frage: Wie   erstellen Sie die Ansichten? ich benutze   RelayCommands zu binden, die aus der   Blick zum Ansichtsmodell, so die Ansicht   weiß nicht einmal eine Aktion   gefeuert, weiß nicht, dass er ein geöffnet werden soll   neue Ansicht. Lösung: Erstellen Sie eine Veranstaltung in   die VM für die Ansicht abonnieren Sie?

Als ich ursprünglich MV-VM Entwicklung begonnen hatte ich diese Vorstellung, dass alles in dem Ansichtsmodell leben soll, und hat viele Beispiele von Leuten wie Josh Smith und Karl Shifflett . Ich habe aber noch mit einem guten Beispiel zu kommen, wenn ein Befehl im Ansichtsmodell zum Leben braucht.

Zum Beispiel, sagen wir, ich ein Listview, die Kunden zeigt, und eine Schaltfläche, die ich erlaube klicken mir die aktuell ausgewählte Kunden zu bearbeiten. Das Listview (Ansicht) auf einen CustomerVM (Viewmodel) gebunden. Durch Anklicken der Schaltfläche löst das EditCustomerCommand, die ein Popup-Fenster öffnet, die mir alle Eigenschaften des CustomerVM bearbeiten können. Wo lebt dieser EditCustomerCommand? Handelt es sich um ein Fenster, (UI-Funktionalität) zu öffnen, sollte es nicht in der Code-Behind der Ansicht definiert werden? alt text

Hat jemand irgendwelche Beispiele, wenn ich einen Befehl in der Ansicht gegenüber dem Ansichtsmodell definieren sollte?

Matthew Wright Staaten unter:

  

Neu und Löschen aus einer Liste wäre   gute Beispiele. In diesen Fällen wird ein Rohling   Datensatz hinzugefügt wird oder der aktuelle Datensatz   wird durch das Ansichtsmodell gelöscht. Irgendein   Maßnahmen der Ansicht genommen sollte sein   Antwort auf diese Ereignisse auftreten.

Also, wenn ich die neue Schaltfläche klicken, was passiert? Eine neue Instanz der CustomerVM wird durch das Mutteransichtsmodell und hinzugefügt erstellt, um es Sammlung ist richtig? So wie dann würde mein Bearbeitungsbildschirm geöffnet werden? Der Blick sollte eine neue Instanz des Kunden Ansichtsmodell erstellen und es in nach rechts ParentVM.Add (newlyCreatedVM) Methode übergeben?

Lassen Sie uns sagen, dass ich über die DeleteCommand leben auf dem VM einen Kundendatensatz löschen. die VM ruft in die Business-Schicht und versucht, den Datensatz zu löschen. Es kann nicht so gibt es eine Nachricht an die VM. Ich möchte diese Nachricht in dialogbox anzuzeigen. Wie kommt die Ansicht, die die Nachricht aus der Kommando-Aktion?

War es hilfreich?

Lösung

Hätte nie gedacht, ich würde sehen, ich in einer Frage zitiert wird.

Ich überlegte mir Frage für einige Zeit, und machte eine eher pragmatische Entscheidung für meine Code-Basis:

In meiner Code-Basis wird das Ansichtsmodell genannt wird, wenn Aktionen geschehen, und ich wollte es auf diese Weise bleiben. Außerdem möchte ich nicht das Viewmodel, die Ansichten zu steuern.

Was habe ich getan?
Ich habe einen Controller für die Navigation:

public interface INavigation
{
  void NewContent(ViewModel viewmodel);
  void NewWindow(ViewModel viewmodel);
}

Dieser Controller enthält zwei Aktionen: newContent () neue Inhalte im aktuellen Fenster nicht zeigt, NewWindow () erzeugt ein neues Fenster, füllt es mit dem Inhalt und zeigt es
. Natürlich haben meine Viewmodel keine Ahnung, was zu zeigen sehen. Aber sie wissen, welche Ansichtsmodell sie zeigen wollen, so nach Ihrem Beispiel, wenn DeleteCommand ausgeführt wird, würde es die Navigationsdienst-Funktion aufrufen NewWindow (neu ValidateCustomerDeletedViewModel ()) ein Fenster zu zeigen, die besagt, ‚den Kunden wurde (für diese einfache messagebox treibt, aber es wäre einfach eine spezielle Navigator-Funktion zur einfachen Message hat) gelöscht.‘

Wie funktioniert das Viewmodel den Navigationsdienst bekommen?

Meine Viewmodel-Klasse hat eine Eigenschaft für die Navigationssteuerung:

public class ViewModel
{
  public INavigation Navigator { get; set; }
  [...]
}

Wenn ein Ansichtsmodell an ein Fenster angebracht ist (oder was auch immer zeigt die Ansicht), wird das Fenster mit der Navigator-Eigenschaft, so dass das Viewmodel kann es nennen.

Wie der Navigator die Ansicht auf das Ansichtsmodell erstellen?

Sie können eine einfache Liste haben, die in meinem Fall für die Ansichtsmodell zu schaffen, sehen kann ich einfache Überlegung verwenden, da die Namen passen:

public static FrameworkElement CreateView(ViewModel viewmodel)
{
  Type vmt = viewmodel.GetType();
  // big bad dirty hack to get the name of the view, but it works *cough*
  Type vt = Type.GetType(vmt.AssemblyQualifiedName.Replace("ViewModel, ", "View, ")); 
  return (FrameworkElement)Activator.CreateInstance(vt, viewmodel);
}

Natürlich muss die Ansicht, die einen Konstruktor das Viewmodel als Parameter akzeptieren:

public partial class ValidateCustomerDeletedView : UserControl
{
  public ValidateCustomerDeletedView(ValidateCustomerDeletedViewModel dac)
  {
    InitializeComponent();
    this.DataContext = dac;
  }
}

Wie sieht mein Fenster aus?

Ganz einfach: mein Hauptfenster funktioniert die INavigation-Schnittstelle implementieren, und zeigt eine Startseite auf Schöpfung. Überzeugen Sie sich selbst:

public partial class MainWindow : Window, INavigation
{
  public MainWindow()
  {
    InitializeComponent();
    NewContent(new StartPageViewModel());
  }

  public MainWindow(ViewModel newcontrol)
  {
    InitializeComponent();
    NewContent(newcontrol);
  }

  #region INavigation Member
  public void NewContent(ViewModel newviewmodel)
  {
    newviewmodel.Navigator = this;
    FrameworkElement ui = App.CreateView(newviewmodel);
    this.Content = ui;
    this.DataContext = ui.DataContext;
  }

  public void NewWindow(ViewModel viewModel)
  {
    MainWindow newwindow = new MainWindow(viewModel);
    newwindow.Show();
  }
  #endregion
}

(Das funktioniert genauso gut mit einem Navigation und das Einwickeln des Blicks in einer Seite)

Natürlich ist prüfbar, da die Navigationssteuerung leicht verspottet werden kann.

Ich bin nicht wirklich sicher, ob dies ist eine perfekte Lösung, aber es funktioniert für mich schön jetzt. Alle Ideen und Kommentare sind willkommen!

Andere Tipps

Für Ihr Löschmeldungsfeld Fall, ich abstrahieren Message über eine Schnittstelle. Ähnlich wie dies. Ich spritze auch diese Schnittstellen für meine WPF-Anwendung.

Constructor

    public MyViewModel(IMessage msg)
    {
      _msg = msg;
    }

Dann wird in dem Verfahren löscht Methode auf dem Viewmodel ... so etwas wie

    public void Delete()
    {
      if(CanDelete)
      {
        //do the delete 
      }
      else
      {
        _msg.Show("You can't delete this record");
      }
    }

Dies wird es testbar machen, die Sie in einer anderen IMessage Implementierungen stecken können, die nicht wirklich eine messagebox zeigen. Diejenigen, könnte nur auf der Konsole drucken, zu Testzwecken. Offensichtlich Ihre WPF-Anwendung könnte eine Implementierung haben wie

public class MessageBoxQuestion : IMessage
{
   public void Show(string message)
   {
     MessageBox.Show(message);
   }
}

Dadurch macht die verschiedenen Routen zu testen (man denke Ja / Nein-Dialoge) sehr einfach und geradlinig. Sie können eine Löschbestätigung vorstellen. Sie entweder eine konkrete Instanz der IMessage verwenden könnten wahr / falsch zur Bestätigung zurückkommen oder den Behälter während des Tests verspotten.

[Test]
public void Can_Cancel_Delete()
{
  var vm = new ProductViewModel(_cancel);
  ...

}
[Test]
public void Can_Confirm_Delete()
{
  var vm = new ProductViewModel(_yes);
  ...

}

Für Ihre andere Frage auf, wenn der Befehl zu verwenden, instanziieren ich das Hinzufügen neuer oder Einzelheiten Ansichten aus der Sicht in Frage. So wie Sie in Ihrem Beispiel haben. Ansichten sind nur durch andere Ansichten in unserer App instanziiert. Ich habe keinen Befehl in den Fällen verwendet werden. Ich jedoch verwenden, um das Ansichtsmodell Eigenschaften der Eltern im Hinblick auf die untergeordneten Ansicht.

public void Object_DoubleClick(object sender, EventArgs e)
{
  var detailView = new DetailView(ViewModel.Product);
  detailView.Show();
}

Hope, das hilft!

Neu und Löschen aus einer Liste würde gute Beispiele sein. In diesen Fällen wird ein leerer Datensatz hinzugefügt oder die aktuelle Datensatz wird durch das Ansichtsmodell gelöscht. Die Maßnahmen der Ansicht genommen sollten als Reaktion auf diese Ereignisse vorkommen.

Eine Möglichkeit wäre, ein Befehlsparameter-Objekt zu verwenden, dass die Business-Schicht ändern kann und Ihre VM können nach dem Befehl in ausgeführt verarbeiten.

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