2016-07-29 41 views
0

Ich habe eine Ansicht, die zwei Teilansichten auf sie hat und ein Ansichtsmodell ist jede Ansicht zugewiesen:Pass-Daten aus dem Code hinter und Ansichtsmodell zu einem anderen Ansichtsmodell

ViewParent - ViewModelParent 
{ 
    ViewA - ViewModelA 
    ViewB - ViewModelB 
} 

Die ViewParent Struktur unten mag.

<StackPanel Orientation="Vertical"> 
    <local:AView DataContext="{Binding ViewModelA, Mode=TwoWay}"></localViews:AView> 
</StackPanel> 
<StackPanel Orientation="Vertical"> 
    <localViews:BView DataContext="{Binding ViewModelB, Mode=TwoWay}"></localViews:BView> 
</StackPanel> 

nun in Code hinter dem ViewA, ich habe ein Ereignis eine Zeile in einem Gridview zu wählen.

private void radGridView_SelectionChanged(object sender, SelectionChangeEventArgs e) 
    { 
     try 
     { 
      RadGridView grv = sender as RadGridView;      

      if (e.AddedItems.Count > 0) 
      { 
       var row = grv.SelectedItem as SomeClass; 
       if(condition) 
        // Enable a button in ViewB. 

Was ich will, ist row zu ViewModelB passieren. Außerdem möchte ich eine Schaltfläche in ViewB aktivieren. Schließlich möchte ich ein paar ganze Zahlen von ViewModelA bis ViewModelB übergeben.

Wie geht das? Ich dachte über Konstruktoreinspritzung nach, aber immer noch ohne klare Vorstellung.

+0

ViewModelParent sollte einen Verweis auf jedes Kind vm haben, richtig? Geben Sie also vmA eine SelectedRow-Eigenschaft mit 'PropertyChanged', und binden Sie diese in ViewA. Geben Sie vmA ein SelectedRowChanged-Ereignis. Erhöhen Sie es, wenn sich die ausgewählte Zeile ändert. ViewModelParent richtet einen Handler für dieses Ereignis ein, wenn er vmA erstellt, und im Handler legt er eine Eigenschaft für vmB fest, wie 'bool CanDoWhatever'. 'CanDoWhatever' aktiviert den Befehl, an den die Schaltfläche gebunden ist, und sieht, dass das CanExecuteChanged-Ereignis des Befehls ausgelöst wird. –

+0

@EdPlunkett, ja. ViewModelParent hat einen Verweis auf jedes untergeordnete vm. Und VmA verfügt bereits über eine SelectedItem-Eigenschaft mit 'PropertyChanged'. Und ich bin mir nicht sicher, was ich in VmB alles machen kann. – Bigeyes

+0

Tun Sie alles, was Sie mit den Werkzeugen haben müssen, die Sie haben. Vielleicht geben Sie vmB eine Eigenschaft 'bool IsMyPuppyDogButtonEnabled {get; einstellen; } 'das erhöht PropertyChanged. Lassen Sie das Eltern-vm diese Eigenschaft in XAML 'IsEnabled =" {Binding IsMyPuppyDogButtonEnabled} "und auf dem Button entsprechend setzen' '. Es gibt eine Million Möglichkeiten, es zu tun. Fazit: Viewmodels verwalten den Status untereinander. Ansichten sitzen dort, beobachten die Eigenschaften ihrer Ansichtsmodelle und reagieren auf Änderungen in diesen Eigenschaften. –

Antwort

1

Hier wird viel geschrieben, aber es gibt keine schwierige Logik und es gibt nichts, was sich in einen Bug verwandelt und dich beißt.

  1. Stellen Sie sicher, ParentViewModel Verweise auf ViewModelA und ViewModelB hat (wie ich es verstehe bist du schon da).

  2. Geben ViewModelA ein SelectedRowChanged Ereignis:

    public event EventHandler SelectedRowChanged; 
    
  3. Geben ViewModelB eine IsMyButtonEnabled Eigenschaft (aber nennen Sie es besser als das, müssen Sie den Namen, um anzuzeigen, die-Taste, um seinen Bezug)

    private bool _isMyButtonEnabled; 
    public bool IsMyButtonEnabled { 
        get { return _isMyButtonEnabled; } 
        set { 
         _isMyButtonEnabled = value; 
         OnPropertyChanged(nameof(IsMyButtonEnabled)); 
        } 
    } 
    
  4. In ViewB, binden Sie die Eigenschaft der Schaltfläche IsEnabled zu t Hut Eigenschaft:

    <Button 
        ... 
        IsEnabled="{Binding IsMyButtonEnabled}" 
        ... 
    
  5. Beide geben ViewModelA und ViewModelB eine SelectedRow Eigenschaft.

    private SomeClass _selectedRow; 
    public SomeClass SelectedRow { 
        get { return _selectedRow; } 
        set { 
         _selectedRow = value; 
         OnPropertyChanged(nameof(SelectedRow)); 
         /* 
          DO ADDITIONAL STUFF HERE: 
    
          VMA: 
           SelectedRowChanged?.Invoke(this, EventArgs.Empty); 
    
          VMB: 
           Set IsMyButtonEnabled to whatever is appropriate based on 
           the selected row. 
         */ 
        } 
    } 
    
  6. ParentViewModel setzt einen Handler für ViewModelA.SelectedRowChanged auf, die es tun kann, weil es einen Verweis auf seine Instanz von ViewModelA hat. Dann teilt der Handler ViewModelB mit, was zu tun ist, wenn SelectedRow sich ändert. Eine andere Möglichkeit wäre, ViewModelB einen Verweis auf ViewModelA zu geben, und es ViewModelA.SelectedRowChanged behandeln. Aber in der Regel möchten Sie, dass Ihre Kindsichtmodelle lockerer gekoppelt sind. Sie wollen nicht, dass B mit einem Geschwister von Typ A abhängen. Aber das Elternteil bereits hängt davon ab, diese beiden Kinder zu haben. Für einen Penny, für ein Pfund. Sie können nicht mehr nass werden.

    ... 
    // Constructor or someplace 
    this.VMA = new ViewModelA(); 
    this.VMA.SelectedRowChanged += ViewModelA_SelectedRowChanged; 
    ... 
    
    void ViewModelA_SelectedRowChanged(Object sender, EventArgs e) 
    { 
        // VMB.SelectedItem's setter will enable the button appropriately 
        VMB.SelectedItem = VMA.SelectedItem; 
    } 
    

Sie wirklich „sollte“ auf die Schaltfläche Sache mit einem Befehl tun, und ermöglicht den Befehl stattdessen eine Is*ButtonEnabled Eigenschaft hat. Das ist eine vielseitigere und leistungsfähigere Art, Dinge zu tun. Aber wir können die Dinge Schritt für Schritt übernehmen.

+0

In Schritt 6, ist es ein Tippfehler? 'VMB.SelectedItem = VMB.SelectedItem;'. Ich verstehe die meisten von ihnen mit Ausnahme der SelectedItem in beiden Orten übereinstimmt. – Bigeyes

+0

@Bigeyes Sicher war ein Tippfehler. Vielen Dank. Behoben. Die SelectedItem-Eigenschaften * stimmen nicht überein - es gibt einen Teil, der sich unterscheidet, den ich in einen Kommentarblock ("DO ZUSÄTZLICHES MATERIAL HIER") setze, der erklärt, wie jede der zwei A/B vm-Klassen ihr eigenes spezielles Bit des Codes hinzufügt . –

+0

Die Sache ist, der Button in ViewB ist immer noch deaktiviert, auch wenn ich es im Setter-Teil des 'SelectedItem'-Eigenschaftsblocks (ViewB) als wahr setze. Übrigens rufe ich das Zeilenänderungsereignis im Code von ViewA statt ViewModelA.cs auf. Nicht sicher, ob es die Ursache ist. Ich habe gesehen, dass Sie das Ereignis selectedItem change in den Setter-Teil von ViewModelA gesetzt haben. Aber ich muss es in den Code hinter der Klasse einfügen. – Bigeyes