2009-05-09 12 views
24

Je regardais MEF comme un cadre d'extensibilité, et je suis assez vendu, sauf pour un point:Utilisation de MEF pour importer un DataTemplate WPF?

Disons que je veux importer à la fois un ViewModel et une vue pour l'afficher. Je pense que la "bonne" manière de le faire est pour la partie MEF d'exporter une classe ViewModel, et un DataTemplate qui affiche le ViewModel. Par exemple, supposons que vous construisiez une application similaire à Visio et que vous souhaitiez importer une bibliothèque de formes. Chaque forme a besoin d'une vue définie dans Xaml et d'un ViewModel qui entoure un objet Model sous-jacent.

Est-ce possible? À quoi ressemblerait le contrat d'importation pour DataTemplate et comment informer WPF du DataTemplate importé?

Répondre

39

Oui, j'ai pu faire ce travail de la manière suivante:

Dans mon hôte application WPF, j'ai ajouté cette importation:

[ImportMany("ApplicationResources", typeof(ResourceDictionary))] 
    public IEnumerable<ResourceDictionary> Views { get; set; } 

Ensuite, dans ma pièce composite, je déclare une ViewModel et un modèle de données pour ViewModel dans un fichier ResourceDictionary Xaml standard. Ensuite, j'ai créé un code derrière le ResourceDictionary, comme celui-ci (dans cet exemple, le ViewModel est appelé ItemViewModel et le ResourceDictionary est appelé ItemView):

[Export("ApplicationResources", typeof(ResourceDictionary))] 
public partial class ItemView : ResourceDictionary 
{ 
    public ItemView() 
    { 
     InitializeComponent(); 
    } 
} 

Pour référence, le XAML pour l'exemple ResourceDictionary ressemble à ceci:

<ResourceDictionary 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="clr-namespace:MyCompany.MyProduct" 
    x:Class="MyCompany.MyProduct.ItemView"> 

    <DataTemplate DataType="{x:Type local:ItemViewModel}"> 
     ... 
    </DataTemplate> 

</ResourceDictionary> 

Puis, dans mon application hôte WPF, après que je compose avec succès et avant que je montre la fenêtre principale, je le fais:

// Add the imported resource dictionaries 
// to the application resources 
foreach (ResourceDictionary r in Views) 
{ 
    this.Resources.MergedDictionaries.Add(r); 
} 

Cela semble appliquer avec succès le DataTemplate partout où WPF voit un ItemViewModel.

EDIT: Pour toute personne intéressée, je a publié un cadre d'application appelée SoapBox Core en open source, et il utilise cette méthode extensive pour importer une vue sur les ressources d'application. Cela fonctionne très bien, et vous pouvez télécharger la source vous-même et voir comment cela fonctionne.

+0

J'ai essayé cette approche exacte mais ResourceDictionary est vide au moment du chargement. Existe-t-il un moyen de forcer l'initialisation ou est-ce que je fais quelque chose de mal? –