2017-06-21 4 views
0

Je développe une application WPF avec le framework Prism MVVM. Et je ne sais pas comment passer correctement les données entre les modèles de vue parent et enfant.Comment lier à la propriété du modèle de vue enfant dans l'application WPF?

J'ai deux modes de vue - ParentViewModel et ChildViewModel intérieur.

public class ParentViewModel 
{ 
    public ParentViewModel 
    { 
     ChildViewModel = new ChildViewModel(params); 
    } 

     private ChildViewModel _childViewModel; 
     public ChildViewModel ChildViewModel 
     { 
      get { return _childViewModel; } 
      set 
      { 
       SetProperty(ref _childViewModel, value); 
      } 
     } 

     //This is does not work 
     public int SelectedChildNumber 
     { 
      return _childViewModel.SelectedNumber; 
     } 
} 

public class ChildViewModel 
{ 
    public ChildViewModel 
    { 
     _numbers = new List<int>(); 
    } 

    private List<int> _numbers; 
    public List<int> Numbers 
    { 
     get { return _numbers; } 
     set 
     { 
      SetProperty(ref _numbers, value); 
     } 
    } 

    private int _selectedNumber; 
    public int SelectedNumber 
    { 
     get { return _selectedNumber; } 
     set 
     { 
      SetProperty(ref _selectedNumber, value); 
     } 
    } 
} 

Je souhaite obtenir et utiliser la valeur sélectionnée du modèle de vue enfant. Mon approche ne fonctionne pas - SelectedChildNumber ne veut pas s'actualiser si SelectedNumber change dans ChildViewModel.

MISE À JOUR: Ok, que faire si j'ai la collection ChildViewModel dans ParentViewModel. Un de ces ChildViewModels a la propriété IsSelected égale à true. Comment obtenir ce modèle de vue sélectionné de la collection?

public class ParentViewModel 
{ 
    public ParentViewModel 
    { 
     Items = GetItems(); 
    } 

    private ObservableCollection<ChildViewModel> _items; 
    public ObservableCollection<ChildViewModel> Items 
    { 
     get 
     { 
      return _items; 
     } 
     set 
     { 
      SetProperty(ref _items, value); 
     } 
    } 
} 

public class ChildViewModel 
{ 
    public ChildViewModel 
    { 
    } 

    private bool _isSelected; 
    public bool IsSelected 
    { 
     get { return _isSelected; } 
     set 
     { 
      SetProperty(ref _isSelected, value); 
     } 
    } 
} 

Comment obtenir le modèle de vue sélectionné? Peut-être utiliser un convertisseur?

<someUserControl DataContext="{Binding ParentViewModel.Items, Converter={x:Static c:GetSelectedItemConverter.Instance}}" /> 

Dans le convertisseur, je peux trouver l'élément sélectionné. Ou c'est une mauvaise idée?

MISE À JOUR 2:

Ok, j'ai battu ce problème avec Ed Plunkett aide. La version finale devrait être:

public class ParentViewModel 
{ 
    public ParentViewModel 
    { 
     Items = GetItems(); 
     foreach (var item in Items) 
     { 
      item.PropertyChanged += ChildViewModel_PropertyChanged; 
     } 
    } 

    private ObservableCollection<ChildViewModel> _items; 
    public ObservableCollection<ChildViewModel> Items 
    { 
     get 
     { 
      return _items; 
     } 
     set 
     { 
      SetProperty(ref _items, value); 
     } 
    } 

    private ChildViewModel _selectedChild; 
    public ChildViewModel SelectedChild 
    { 
     get { return _selectedChild; } 
     set 
     { 
      SetProperty(ref _selectedChild, value); 
     } 
    } 

    private void ChildViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e) 
    { 
     var child = (ChildViewModel)sender; 
     if (e.PropertyName == nameof(ChildViewModel.IsSelected) && child.IsSelected) 
     { 
      SelectedChild = child; 
     } 
    } 
} 
+0

Augmentez-vous l'événement PropertyChanged dans le paramètre SelectedNumber setter? – taquion

+0

Étant donné que j'utilise le framework Prism, je n'ai pas besoin d'augmenter la gestion des événements PropertyChanged. – Oblomingo

+0

@taquion 'SetProperty()' fait cela. Il est bon. –

Répondre

1

Bind directement à la propriété de l'enfant:

<ListBox 
    ItemsSource="{Binding ChildViewModel.Numbers}" 
    SelectedItem="{Binding ChildViewModel.SelectedNumber}" 
    /> 

<Label Content="{Binding ChildViewModel.SelectedNumber}" /> 

C'est le nom de ChildViewModelpropriété du parent dans la voie de liaison, pas le type. Le Binding sait maintenant pour écouter l'objet ChildViewModel pour les notifications PropertyChanged concernant SelectedNumber et Numbers.

La raison pour laquelle votre version ne fonctionne pas est que le parent ne lève pas PropertyChanged lorsque SelectedChildNumber change. En fait, le parent ne sait pas quand il change plus que l'interface utilisateur. Le parent pouvait gérer l'événement PropertyChanged de l'enfant, et parfois c'est fait.

public ParentViewModel() 
{ 
    ChildViewModel = new ChildViewModel(params); 

    // Handle child's PropertyChanged event 
    ChildViewModel.PropertyChanged += ChildViewModel_PropertyChanged; 
} 

private void ChildViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e) 
{ 
    var child = (ChildViewModel)sender; 

    if (e.PropertyName == nameof(ChildViewModel.SelectedNumber)) 
    { 
     // Do stuff 
    } 
} 

Mais vous n'avez pas besoin de faire cela pour des cas comme celui-ci.

ChildViewModel.Numbers devrait probablement être ObservableCollection<int>, et non List<int>. De cette façon, si vous ajoutez plus de numéros ou en supprimez, l'interface utilisateur sera automatiquement notifiée par la collection et le ListBox se mettra automatiquement à jour en conséquence.

+0

Super! Que faire si j'ai une collection ChildViewModel dans ParentViewModel. Un de ces ChildViewModels a la propriété IsSelected égale à true. Comment obtenir ce modèle de vue sélectionné de la collection? – Oblomingo

+1

Dans ce cas, le parent peut souhaiter gérer l'événement 'PropertyChanged' de chaque enfant.C'est drôle, j'ajoutais juste cette idée dans une mise à jour quand j'ai vu votre commentaire. –

+0

Je n'ai aucune idée de comment élever des événements de chaque enfant. Pouvez-vous donner un exemple ? – Oblomingo