2016-08-08 11 views
-1

Ich kann das einfach nicht herausfinden. Also werde ich versuchen, mein Problem so gut wie möglich zu beschreiben.Pass Daten über Viewmodels

Ich baue Anwendung mit MVVM-Muster. Ich habe Benutzersteuerelement AAAView mit Viewmodel AAAViewModel das verwendet wird, um Datenklasse CDataClass zu füllen. Ich habe auch Hauptfenster MainView und sein Viewmodel MainViewModel. Als nächstes habe ich das Fenster mit DialogViewModel.

So jetzt MainViewModel (das hat ein eigenes Benutzersteuerelement) erstellt DialogViewModel (mit einer anderen Instanz der Benutzersteuerung). Wie kann ich Daten zwischen diesen beiden Benutzersteuerelementen in CDataClass übertragen? Ich habe versucht, Eigenschaft in AAAViewModel zu schaffen, die Instanz von MainViewModel oder DialogViewModel halten würde, also kann ich Daten ihm übergeben, aber ich bleibe stecken, weil ich es nicht als Abhängigkeitseigenschaft bilden konnte.

Image representation of problem

Mein Ziel ist es Benutzerkontrolle zu machen, die in verschiedenen Ansichten verwendet werden können, die CDataClass unterschiedliche Daten in underlaying haben.

Nur um zu klären ... Ich benutze Benutzersteuerung als <views:GeneralInfoView Grid.Row="0" /> und weiß nicht, wie Sie Daten zwischen zwei verschiedenen Instanzen des gleichen Benutzersteuerelements in verschiedenen Ansichten teilen. Irgendein Punkt zu irgendeinem Muster oder zu einer Methode würde viel schätzen.

Vielen Dank für Ihre Hilfe.

+0

Wenn die Daten von CDataClass zwischen diesen beiden Ansichten unterschiedlich sind, dann sind sie im Grunde getrennte Instanzen, nicht wahr? – Steve

+0

http://StackOverflow.com/q/3801681/2470362 –

Antwort

1

Ich denke nicht, dass es ideal ist, dass Sie Ihre Anwendungsarchitektur als Beziehungen zwischen Ansichten dargestellt haben; Ich denke, ein besserer Weg, darüber nachzudenken, ist eine Reihe von Beziehungen zwischen den Viewmodels, wobei die Ansichten bei Bedarf von diesem Baum herunterhängen. Wenn Sie so darüber nachdenken, "wie werden Daten weitergegeben?" Wird viel einfacher. Eine Ansicht ist nur eine Verbindung zwischen einem Ansichtsmodell und dem Benutzer. Du entwirfst kein Haus als Fenster und Telefone und versuchst dann den Grundriss daraus zu bestimmen. Du beginnst damit, was das Haus macht und wie die Leute darin leben werden.

Das ist also einfach:

Einige Viewmodels haben eine AAViewModel Eigenschaft. Es kann alle Arten von einfachen oder komplizierten Ansichten auf diesen Viewmodels geben; Wenn eine Ansicht den Benutzer die AAViewModel Sachen des Viewmodels bearbeiten lassen möchte, dann enthält es eine AAView, die passend an das Viewmodel AAViewModel gebunden ist. Ihre MainViewModel und DialogViewModel sind beide große komplizierte interaktive Ansichten, die jemand ihre vms AAViewModel Zeug bearbeiten lassen wollen.

Wenn MainViewModel ist DialogViewModel ‚s Elternteil oder eine temporäre Instanz von DialogViewModel erstellt nur in einem modalen Dialog zu setzen, dann würde MainViewModel den Dialog zeigen, und hat einen Blick auf dialogVM.AAVM.CData.IsDirty zu entscheiden, was damit zu tun. Oder vielleicht gibt es dialogVM.AAVM eine neue CDataClass Instanz vor dem Anzeigen des Dialogfelds (vielleicht ein Klon seiner eigenen Instanz), und wenn ShowModel()true zurückgibt, dann tut es etwas mit dialogVM.AAVM.CData.

Der Punkt ist, dass, sobald Ihre Viewmodels alles fahren, wird es relativ einfach für sie miteinander zu kommunizieren. Eltern-Kind ist einfach: Eltern geben dem Kind Zeug und schauen, was das Kind zurückbringt. Ein Viewmodel kann das Ereignis PropertyChanged eines anderen Viewmodels abonnieren. Ein Eltern-View-Modell kann seine Kinder überwachen. Wenn bei einem Kind etwas passiert, kann der Elternteil entscheiden, ob er ein Geschwister aktualisiert.Im Allgemeinen sollten Kinder nichts über ihre Eltern wissen; Dies macht es viel einfacher, Kind View-Modelle in unterschiedlichen Kontexten wiederzuverwenden. Es liegt an den Eltern zu entscheiden, was mit diesen Informationen zu tun ist.

Alle AAViewModel weiß, ist, dass jemand ihm eine Kopie von CDataClass geben; Er aktualisiert seine öffentlichen Eigenschaften entsprechend. Dann übergibt ihm jemand anderes (wahrscheinlich AAView, aber er weiß es nicht) einige Änderungen, indem er seine Eigenschaften einstellt; Er aktualisiert seine CDataClass Instanz entsprechend. Nach einer Weile, die ihm unbekannt ist, kommt das eine oder andere Modell und schaut sich das CDataClass an.

Die Kommunikation zwischen Ansichten und Viewmodels erfolgt über Bindungen.

UPDATE

Es stellt sich heraus, dass Sie Viewmodel in Ihren Ansichten, und als Ergebnis haben Sie keine Ahnung haben, sind zu schaffen, wie die Eltern, um sie zu bekommen. Und jetzt wissen Sie, warum es keine gute Idee ist, untergeordnete Ansichtsmodelle auf diese Weise zu erstellen.

Hier ist, wie Sie Kind Ansicht/Viewmodel in dem Viewmodel-zentriert Design ich oben beschrieben:

Zuerst loszuwerden, was auch immer du tust, das Kind Viewmodel in der Ansicht zu erstellen.

Zweitens eine DataTemplate für die Art Kind Ansichtsmodell erstellen. Dies sollte in einem Ressourcenwörterbuch gehen, das mit den Ressourcen in App.xaml zusammengeführt wird, aber es ist so einfach, dass es Sie nicht tötet, wenn Sie faul werden und es einfach in die Resources der zwei verschiedenen Ansichten einfügen, wo es verwendet wird.

Ich weiß nicht, wie Ihre Namespace-Deklarationen aussehen. Ich gehe davon aus, dass Ansichten in etwas sind, das xmlns:view="..." genannt wird, und Viewmodels sind in etwas, das xmlns:vm="..." genannt wird.

<DataTemplate DataType="{x:Type vm:AAAViewModel}"> 
    <view:AAAView /> 
</DataTemplate> 

Jetzt können Sie einen AAAViewModel zum ContentProperty jeglicher Kontrolle zuweisen, die von ContentControl erbt (und das ist die meisten von ihnen), und die Vorlage instanziiert werden. Das bedeutet, dass XAML für Sie eine AAAView erstellt und die Instanz AAAViewModel der -Eigenschaft der AAAView, die es gerade erstellt hat, zuweist.

Also lassen Sie sich AAAViewModel als nächstes ein Kind erstellen, und dann werden wir es in der Benutzeroberfläche angezeigt.

public class DialogViewModel 
{ 

    // You can create this in DialogViewModel's constructor if you need to 
    // give it parameters that won't be known until then. 
    private AAAViewModel _aaavm = new AAAViewModel(); 
    public AAAViewModel AAAVM 
    { 
     get { return _aaavm; } 
     protected set { 
      _aaavm = value; 
      OnPropertyChanged(nameof(AAAVM)); 
     } 
    } 

Und jetzt können wir AAAVM in DialogView anzuzeigen:

<Grid> 
    <Grid.RowDefinitions> 
     <RowDefinition Height="Auto" /> 
     <RowDefinition Height="*" /> 
    </Grid.RowDefinitions> 

    <ContentControl 
     Content="{Binding AAAVM}" 
     Grid.Row="0" 
     /> 

    <StackPanel Orientation="Vertical" Grid.Row="1"> 
     <!-- Other stuff --> 
    </StackPanel> 
</Grid> 

Nun, wie funktioniert MainViewModel mit einem DialogViewModel kontaktieren? Im Falle von Dialogen, da sie eine begrenzte Lebensdauer haben, ist es nicht wirklich eine große Sache, dass sie ihre eigenen Ansichtsmodelle erstellen können. Du kannst es so oder so machen. Ich lehne es generell an, es wie im zweiten Beispiel unten erstellen zu lassen.

Nicht ganz gleich, aber nah. Als Erstes werden Sie wieder los, was auch immer Sie tun, wenn der Dialog ein eigenes Ansichtsmodell erstellt.

MainViewModel.cs

public CDataClass CDC { /* you know the drill */ } 

public void ShowDialog() 
{ 
    var dvm = new DialogViewModel(); 

    // Maybe this isn't what you want; I don't know what CDataClass does. 
    // But I'm assuming it has a copy constructor. 
    dvm.AAAVM.CDC = new CDataClass(this.CDC); 

    if (DialogView.ShowDialog(dvm).GetValueOrDefault()) 
    { 
     CDC = dvm.CDC; 
    } 
} 

Beachten Sie, dass das nächste Codebehind anzeigen, nicht Viewmodel ist.

DialogView.xaml.cs

public static bool? ShowDialog(DialogViewModel dvm) 
{ 
    var vw = new DialogView() { DataContext = dvm }; 

    return vw.ShowDialog(); 
} 

Nun Sie der Dialog fortsetzen lassen könnte sein eigenes Ansichtsmodell zu schaffen; in diesem Fall würden Sie es eine öffentliche Eigenschaft wie folgt geben:

public DialogViewModel ViewModel => (DialogViewModel)DataContext; 

Und ein Showdialog-Methode wie folgt aus:

DialogView.xaml.cs

public static bool? ShowDialog(CDataClass cdc) 
{ 
    var dlg = new DialogView(); 

    dlg.ViewModel.AAAVVM.CDC = cdc; 

    return dlg.ShowDialog(); 
} 

Und dann könnte die Eltern interagieren mit es wie folgt statt:

MainViewModel.cs

public void ShowDialog() 
{ 
    var cdcClone = new CDataClass(this.CDC); 

    if (DialogView.ShowDialog(cdcClone).GetValueOrDefault()) 
    { 
     CDC = cdcClone; 
    } 
} 

Schön und sauber.

Wenn dieser Dialog nicht modal ist, machen Sie das Dialogfeld viewmodel zu einem privaten Mitglied von MainViewModel, und lassen Sie sich Ereignisse im Dialog ViewModel abonnieren, um auf dem Laufenden zu bleiben, was der Dialog macht. Immer wenn der Benutzer die Kopie des Dialogs von CDataClass aktualisiert, würde der Dialog DataClassUpdated auslösen, und MainViewModel würde einen Handler für dieses Ereignis haben, der bei _dialogViewModel.AAAVM.CDC schnüffelt und entscheidet, was damit zu tun ist. Wir können dafür bei Bedarf Beispielcode bekommen.

So jetzt können Sie sehen, was ich meine, indem ich alles in Bezug auf Eltern/Kind Viewmodels aufbaute, und sie in Views stopfte, wenn und wie passend.

+0

Ok ich habe es. Aber wie bekomme ich etwas von AAAViewModel, wenn ich keinen Zugriff darauf habe? AAAViewModel wird automatisch mit View erstellt, nicht aus Code. Die Benutzerkontrollansicht ist in DialogView in xaml als definiert, daher kann ich nicht sehen, wie ich von DialogViewModel aus auf viewmodel dahinter zugreifen kann. – benderto

+0

@benderto Deshalb erstellst du deine Viewmodels nicht so! Wenn ich in ein oder zwei Stunden ins Büro komme, zeige ich dir, wie man es als DataTemplate macht. –

+0

@benderto Aktualisierte Antwort. –