jenswinter.com
Software Development 24/7

Einführung in das Managed Extensibility Framework (Teil 3)

October 7, 2008 20:15 by Jens

Bisherige Artikel der Serie:


Im vorigen Artikel habe ich gezeigt, wie mit Hilfe des MEF einem TabControls Seiten hinzugefügt werden können, ohne dass die Seiten explizit erzeugt werden müssen. Die Aufgabe der Erzeugung übernimmt dabei das MEF.

In diesem Artikel geht es um die Verwendung und Auswertung von Metadaten.
Wenn man sich nochmal den Quelltext des Hauptfensters aus dem letzten Beispiel anschaut, so fällt eine sehr unschöne Sache auf:

public partial class MainWindow : Window
{
    [Import("Page1")]
    public UserControl Page1;

    [Import("Page2")]
    public UserControl Page2;
    
    [Import("Page3")]
    public UserControl Page3;

    public MainWindow()
    {
        InitializeComponent();

        var catalog = new AttributedAssemblyPartCatalog(Assembly.GetExecutingAssembly());
        var container = new CompositionContainer(catalog.CreateResolver());
        container.AddPart(this);
        container.Compose();

        DataContext = new List<object>
                          {
                              new {Title = "Page 1", Page = Page1},
                              new {Title = "Page 2", Page = Page2},
                              new {Title = "Page 3", Page = Page3}
                          };
    }
}

Das Fenster braucht sich zwar nicht mehr um die Herkunft und Erzeugung der Seiten kümmern, muss aber trotzdem wissen, wie die Seiten betitelt werden. Das passt irgendwie nicht zusammen.
Zu sehen ist das ganze beim Zuweisen des DataContext. Die Seiten werden importiert, ohne dass wirklich deren Herkunft bekannt ist, aber die Titel sind fest im Quelltext hinterlegt.

Besser wäre es, wenn die Seiten-Bezeichnungen genauso dynamisch bestimmt werden können, wie die Seiten selbst. Sinnvollerweise sollte jede Seite selbst wissen, wie sie bezeichnet werden soll.
Das Hinterlegen von Meta-Informationen ist mit Hilfe des ExportMetadata-Attributes möglich. Damit können Exports mit Informationen versehen werden, die beim Importieren ausgewertet werden können.

Der Quelltext der Seite Page1 sieht nun so aus:

[Export("Page1")]
[ExportMetadata("Title""Page 1")]
public partial class Page1 : UserControl
{
    public Page1()
    {
        InitializeComponent();
    }
}

Die Klasse Page1 wird hier mit dem ExportMetadata-Attribut versehen, dem ein Schlüssel-Wert-Paar übergeben wird. Der erste Parameter ist der Schlüssel, und lautet in diesem Fall natürlich "Title". Der zweite Parameter ist die tatsächliche Bezeichnung, die im Hauptfenster verwendet werden soll.

Nachdem die anderen Seiten auf dieselbe Weise erweitert wurden, können die Metadaten beim Importieren verwendet werden. Dafür müssen aber zunächst die Imports etwas abgewandelt werden:

[Import("Page1")]
public Export<UserControl> Page1;

[Import("Page2")]
public Export<UserControl> Page2;

[Import("Page3")]
public Export<UserControl> Page3;

Die Seiten sind nun nicht mehr als UserControl deklariert, sondern als Export<UserControl>. Die Export-Klasse verfügt über eine Metadata-Eigenschaft, die mit den entsprechenden Angaben beim Importieren gefüllt werden. Beim Füllen des DataContext können diese Daten dann verwendet werden. An das eigentliche UserControl-Objekt gelangt man über die Methode GetExportedObject():

DataContext = new List<object>
                  {
                      new {Title = Page1.Metadata["Title"], Page = Page1.GetExportedObject()},
                      new {Title = Page2.Metadata["Title"], Page = Page2.GetExportedObject()},
                      new {Title = Page3.Metadata["Title"], Page = Page3.GetExportedObject()}
                  };


Die Anwendung zeigt nach den Änderungen erfreulicherweise noch das gleiche Ergebnis, wie vorher. Allerdings muss das Fenster nun nicht mehr wissen, wie die einzelnen Seiten betitelt werden sollen. Das ist ein großer Schritt in Richtung Erweiterbarkeit.

Der Quelltext der Beispielanwendung kann hier heruntergeladen werden.


Related posts

Comments

October 7. 2008 23:30

Daniel Plaisted

Ich vermute, dies ist nicht das Letzte Artikel in dieser Serie? Weil es meiner Meinung nach recht schöner wäre, ein List für das Import zu benutzen. Dann brauchte das MainWindow gar nicht zu wissen wieviele Zeiten es gibt.

(Excuse my poor German Smile )


Daniel Plaisted

October 7. 2008 23:41

Jens

Hallo Daniel,
Du hast absolut Recht. Genau darauf wollte ich im vierten Teil eingehen.

Jens

Add comment


(Will show your Gravatar icon)  

  Country flag

[b][/b] - [i][/i] - [u][/u]- [quote][/quote]



Live preview

January 7. 2009 11:10