Metadatenspeicher
Aktualisiert: November 2007
Das Windows Presentation Foundation (WPF)-Designer für Visual Studio-Framework entkoppelt Entwurfszeitmetadaten von der Implementierung. Das Trennen der Metadaten vom Laufzeitcode ist aus den folgenden Gründen ein wichtiges Entwurfsprinzip.
Das Erstellen der Turnaround- und Integrationslogistik zwischen Teams kann das Kompilieren von Metadaten in Frameworkcode kompliziert machen.
Das Kompilieren von Metadaten in den Laufzeitcode verhindert, dass externe Tools, beispielsweise der WPF-Designer oder Expression Blend, diese Metadaten später ändern. Dies ist ein wichtiges Problem im Hinblick auf die Flexibilität. Wenn Entwurfszeitmetadaten nicht vom Code entkoppelt werden, kann Visual Studio seinen Designern keine Version zuweisen, ohne dass eine neue Version von .NET Framework erforderlich ist.
Wenn Metadaten in die Laufzeit kompiliert werden, vergrößert sich die Laufzeitassembly bedeutend. Zudem verlangsamen die Entwurfszeitattribute die Laufzeit. Laufzeitfeatures (z. B. Datenbindung), die Reflektion verwenden, sind betroffen, wenn zusätzliche Attribute in den Speicher geladen werden.
Entwurfszeitmetadaten stellen die "Persönlichkeit" des Designers bereit. Die Features eines Designers sind zum größten Teil an die Anwendung gebunden, die den Designer hostet, und nicht an die Laufzeit. Der WPF-Designer und Expression Blend verwenden verschiedene Sätze von Metadaten, um einen Featuresatz für einen spezifischen Benutzertyp bereitzustellen.
Der Metadatenspeicher
Der Metadatenspeicher ist ein Speicherort für Entwurfszeitmetadaten. Die API für den Metadatenspeicher ist einfach. Sie fügen eine Tabelle mit Metadatenattributen hinzu, indem Sie die AddAttributeTable-Methode aufrufen. Wenn eine Tabelle zum Metadatenspeicher hinzugefügt wird, werden die in dieser Tabelle definierten Attribute über TypeDescriptor-Abfragen verfügbar. Wenn ein Typ bereits abgefragt wurde und die Tabelle zusätzliche Attribute für diesen Typ enthält, wird ein Refreshed-Ereignis ausgelöst, um zu berichten, dass sich die Metadaten des Typs geändert haben.
Die Attributtabelle
Eine Attributtabelle ist im Wesentlichen ein schreibgeschütztes Wörterbuch, aber die Schlüssel und Werte werden getrennt berechnet. Es ist effizient, in einer Attributtabelle eine Abfrage für Attribute eines bestimmten Typs durchzuführen. Der tatsächliche Satz von Attributen wird bei Bedarf erstellt. Sie rufen die GetCustomAttributes-Methode auf, um die benutzerdefinierten Metadaten für einen besonderen Typ abzurufen.
In einer Attributtabelle werden nur die Eigenschaften eines Typs unterstützt. In einer Attributtabelle werden keine Attribute für Felder oder Methoden unterstützt.
Der Attributtabellen-Generator
Zur Erstellung einer Attributtabelle erstellen Sie zunächst eine Instanz der AttributeTableBuilder-Klasse. Fügen Sie dem Attributtabellen-Generator Metadaten hinzu, indem Sie die AddCustomAttributes-Überladungen aufrufen. Nachdem Sie die Metadaten hinzugefügt haben, erstellen Sie aus dem Attributtabellen-Generator eine Attributtabelle, indem Sie die CreateTable-Methode aufrufen. Die Methoden des Attributtabellen-Generators unterstützen Rückrufdelegaten. Somit kann die Erstellung der Attributtabelle bis zum gewünschten Zeitpunkt hinausgezögert werden.
Erstellen eines benutzerdefinierten Attributs
Für den Metadatenspeicher ist es erforderlich, dass benutzerdefinierte Attribute eine ordnungsgemäß definierte Überschreibung für ihre TypeId-Eigenschaft besitzen. Der Metadatenspeicher verwendet die TypeId-Eigenschaft, um festzustellen, ob zwei Attribute desselben oder eines anderen Typs als die gleichen Instanzen behandelt werden sollten.
Die Attribute-Basisklasse definiert die TypeId-Eigenschaft wie folgt.
public class Attribute
{
...
public virtual object TypeId
{
get
{
return base.GetType();
}
}
...
}
Durch diese Implementierung erscheinen zwei Instanzen des gleichen Attribute-Typs als das gleiche Attribut. Eine der Instanzen wird von der TypeDescriptor-Standardimplementierung ignoriert. Wenn dies nicht das gewünschte Verhalten eines benutzerdefinierten Attributs ist, wie z. B. bei der FeatureAttribute-Klasse, muss das benutzerdefinierte Attribut die TypeId-Eigenschaft überschreiben, damit ein eindeutiges Objekt für jede Typinstanz zurückgegeben wird. Die FeatureAttribute-Klasse überschreibt beispielsweise die TypeId-Eigenschaft mithilfe des folgenden Codes.
public override object TypeId
{
get { return this; }
}
Da this ein eindeutiges Objekt für jede Objektinstanz darstellt, kann FeatureAttribute dieselbe Klasse gefahrlos mehrmals ergänzen und das gewünschte Resultat erzielen, wenn es in Verbindung mit dem Metadatenspeicher verwendet wird.
Benennungskonvention für Metadatenassemblys
Entwurfszeitcode wird in speziellen Metadatenassemblys bereitgestellt. Entwurfszeitfeatures, die von allen Designern unterstützt werden, werden in einer Assembly bereitgestellt, bei der ".Design" an den Hauptnamen der Bibliothek angehängt wird. Entwurfszeitfeatures, die nur von Visual Studio unterstützt werden, werden in einer Assembly bereitgestellt, bei der ".VisualStudio.Design" an den Hauptnamen der Bibliothek angehängt wird. In der folgenden Tabelle werden Beispielnamen für eine Laufzeitsteuerelementbibliothek mit dem Namen CustomControlLibrary.dll gezeigt.
Designer |
Assemblyname zur Entwurfszeit |
---|---|
Nur Visual Studio |
CustomControlLibrary.VisualStudio.Design.dll |
Nur Expression Blend |
CustomControlLibrary.Expression.Design.dll |
Alle Designer |
CustomControlLibrary.Design.dll |
Laden von Metadatenassemblys
Wenn der Designer eine Laufzeitassembly lädt, sucht er auch nach entsprechenden Metadatenassemblys. Wenn die entsprechenden Metadatenassemblys gefunden werden, werden sie sofort geladen, nachdem die Laufzeitassembly geladen wurde.
Wenn Sie einen neuen Assemblyverweis für das Projekt erstellen, wird nach allen entsprechenden Metadatenassemblys gesucht, und die gefundenen Assemblys werden geladen.
Metadatenassemblys werden neu geladen, wenn sie neu erstellt werden.
Hinweis: |
---|
*.Design.dll-Metadatenassemblys werden vor den designerspezifischen *.VisualStudio.Design.dll-Assemblys und *.Expression.Design.dll-Assemblys geladen. Designerspezifische Metadaten überschreiben freigegebene Metadaten. |
Suchreihenfolge für Metadatenassemblys
Die folgende Suchreihenfolge gilt für Assemblys, auf die direkt vom Projekt verwiesen wird.
Der Designer durchsucht den gleichen Ordner wie die Laufzeitassembly, auf die verwiesen wird. Dieser Speicherort wird gefunden, indem der gleiche Algorithmus verwendet wird, den auch der Build verwendet, um nach der Assembly zu suchen. Dies schließt das Durchsuchen der SDK-Ordner und zusätzlicher Pfade ein.
Der Designer sucht nach einem "Design"-Unterordner in dem Ordner, in dem sich die Laufzeitassembly des Steuerelements befindet.
Auch wenn die Laufzeitassembly eines Steuerelements aus dem globalen Assemblycache (GAC) geladen werden kann, liegt immer ein Verweis auf einen Speicherort außerhalb des GAC vor. Oft befindet sich dieser Speicherort im SDK-Ordner. Der WPF-Designer verwendet Visual Studio-APIs, um eine Assembly, auf die verwiesen wird, im Dateisystem zu suchen, selbst wenn der HintPath des Projekts nicht angegeben ist. Der Designer versucht, die Metadatenassembly von dem Speicherort zu laden, an dem der Verweis auf die Laufzeitassembly des Steuerelements vorliegt, und nicht von dem Ort, an dem die Laufzeitassembly des Steuerelements geladen wird.
Assemblys, auf die indirekt verwiesen wird, werden geladen, da eine Assembly auf sie verweist, auf die das Projekt verweist. Wenn ein Projekt beispielsweise einen Verweis auf die Assembly MyAssembly enthält und MyAssembly einen Verweis auf MyOtherAssembly enthält, auf die vom Projekt nicht direkt verwiesen wird, gilt MyOtherAssembly als Assembly, auf die indirekt verwiesen wird.
In diesem Fall ist die Assembly nicht für den Build erforderlich, und das Buildsystem kann den Speicherort der Assembly, auf die nicht direkt verwiesen wird, im Dateisystem nicht finden. In der folgenden Tabelle wird gezeigt, wie der Designer Assemblys lädt, auf die indirekt verwiesen wird.
Assembly, auf die verwiesen wird |
Suchprozedur |
---|---|
Datei, die aus dem GAC geladen wird |
In SDK-Ordnern wird nach der entsprechenden Metadatenassembly gesucht. Wenn diese Assembly gefunden wird, werden ihr Pfad und ihr "Design"-Unterordner nach entsprechenden Metadatenassemblys durchsucht. |
Datei, die von einem Speicherort außerhalb des GAC geladen wird |
Der Pfad und der "Design"-Unterordner der Laufzeitassembly werden nach entsprechenden Metadatenassemblys durchsucht. |
Suchen nach einer IRegisterMetadata-Implementierung
Metadatenassemblys müssen eine oder mehrere Implementierungen der IRegisterMetadata-Schnittstelle enthalten. Die IRegisterMetadata-Implementierung wird mithilfe der Reflektion gesucht. Wenn in einer Assembly mehrere IRegisterMetadata-Implementierungen enthalten sind, wird jede Implementierung instanziiert und in der Reihenfolge aufgerufen, die von der Reflektions-API zurückgegeben wird.
Siehe auch
Referenz
Microsoft.Windows.Design.Metadata