Comment associer un TabControl à une collection de ViewModels?

Fondamentalement, j’ai dans mon MainViewModel.cs:

ObservableCollection MyTabs { get; private set; } 

Toutefois, je dois non seulement créer les tabs, mais aussi charger et associer le contenu des tabs à leurs modèles de vue appropriés tout en maintenant MVVM.

Fondamentalement, comment puis-je charger un contrôle utilisateur en tant que contenu d’un tabitem ET que ce contrôle utilisateur soit câblé à un modèle de vue approprié. La partie qui rend cela difficile est que ViewModel n’est pas supposé construire les éléments de vue réels, non? Ou peut-il?

Fondamentalement, cela serait-il approprié MVVM:

 UserControl address = new AddressControl(); NotificationObject vm = new AddressViewModel(); address.DataContext = vm; MyTabs[0] = new TabItem() { Content = address; } 

Je ne demande que parce que bien, je construis une vue (AddressControl) à partir d’un ViewModel, qui pour moi ressemble à un MVVM no-no.

Ce n’est pas MVVM. Vous ne devez pas créer d’éléments d’interface utilisateur dans votre modèle de vue.

Vous devez lier le ItemsSource de l’onglet à votre ObservableCollection, qui doit contenir des modèles contenant des informations sur les tabs à créer.

Voici la VM et le modèle qui représente une page à onglet:

 public sealed class ViewModel { public ObservableCollection Tabs {get;set;} public ViewModel() { Tabs = new ObservableCollection(); Tabs.Add(new TabItem { Header = "One", Content = "One's content" }); Tabs.Add(new TabItem { Header = "Two", Content = "Two's content" }); } } public sealed class TabItem { public ssortingng Header { get; set; } public ssortingng Content { get; set; } } 

Et voici comment les liaisons apparaissent dans la fenêtre:

                    

(Remarque: si vous voulez des éléments différents dans des tabs différents, utilisez DataTemplates . Le modèle de vue de chaque onglet doit être sa propre classe ou créez un DataTemplateSelector personnalisé pour choisir le modèle correct.)

Oh regarde, un UserControl à l’intérieur du modèle de données:

               

Dans Prism, vous faites généralement en sorte que l’onglet contrôle une région afin que vous n’ayez pas à prendre le contrôle de la collection de pages à onglet liée.

  

Maintenant, les vues peuvent être ajoutées en s’inscrivant dans la région MainRegion:

 RegionManager.RegisterViewWithRegion( "MainRegion", ( ) => Container.Resolve( ).View ); 

Et ici, vous pouvez voir une spécialité du prisme. La vue est instanciée par le ViewModel. Dans mon cas, je résous le ViewModel via un conteneur Inversion of Control (par exemple, Unity ou MEF). ViewModel obtient la vue injectée via l’injection du constructeur et se définit comme le contexte de données de la vue.

L’alternative consiste à enregistrer le type de la vue dans le contrôleur de région:

 RegionManager.RegisterViewWithRegion( "MainRegion", typeof( MyView ) ); 

L’utilisation de cette approche vous permet de créer les vues ultérieurement lors de l’exécution, par exemple par un contrôleur:

 IRegion region = this._regionManager.Regions["MainRegion"]; object mainView = region.GetView( MainViewName ); if ( mainView == null ) { var view = _container.ResolveSessionRelatedView( ); region.Add( view, MainViewName ); } 

Étant donné que vous avez enregistré le type de la vue, la vue est placée dans la région appropriée.

J’ai un convertisseur pour découpler l’interface utilisateur et ViewModel, c’est le point ci-dessous:

      

L’onglet est une enum dans mon TabItemViewModel et le TabItemConverter le convertit en l’interface utilisateur réelle.

Dans TabItemConverter, récupérez simplement la valeur et renvoyez un contrôle utilisateur dont vous avez besoin.