Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
XAML wie in CLR-Frameworks (Common Language Runtime) implementiert, unterstützt die Möglichkeit, eine benutzerdefinierte Klasse oder Struktur in einer beliebigen ClR-Sprache (Common Language Runtime) zu definieren und dann mithilfe von XAML-Markup auf diese Klasse zuzugreifen. Sie können eine Mischung aus Windows Presentation Foundation (WPF)-definierten Typen und Ihren benutzerdefinierten Typen in derselben Markupdatei nutzen, in der Regel durch Zuordnen der benutzerdefinierten Typen zu einem XAML-Namespace-Präfix. In diesem Thema werden die Anforderungen erläutert, die eine benutzerdefinierte Klasse erfüllen muss, damit sie als XAML-Element verwendet werden kann.
Benutzerdefinierte Klassen in Anwendungen oder Assemblies
Benutzerdefinierte Klassen, die in XAML verwendet werden, können auf zwei verschiedene Arten definiert werden: innerhalb des CodeBehind- oder eines anderen Codes, der die primäre Windows Presentation Foundation (WPF)-Anwendung erzeugt, oder als Klasse in einer separaten Assembly, z. B. eine ausführbare Datei oder DLL, die als Klassenbibliothek verwendet wird. Jeder dieser Ansätze hat besondere Vor- und Nachteile.
Der Vorteil der Erstellung einer Klassenbibliothek besteht darin, dass solche benutzerdefinierten Klassen für viele verschiedene mögliche Anwendungen freigegeben werden können. Eine separate Bibliothek erleichtert auch die Steuerung von Versionsverwaltungsproblemen von Anwendungen und vereinfacht das Erstellen einer Klasse, bei der die beabsichtigte Klassenverwendung als Stammelement auf einer XAML-Seite ist.
Der Vorteil der Definition der benutzerdefinierten Klassen in der Anwendung besteht darin, dass diese Technik relativ einfach ist und die Bereitstellungs- und Testprobleme minimiert, die auftreten, wenn Sie separate Assemblys über die ausführbare Hauptanwendung hinaus einführen.
Ob in derselben oder unterschiedlichen Assemblys definiert, müssen benutzerdefinierte Klassen zwischen CLR-Namespace und XML-Namespace zugeordnet werden, um in XAML als Elemente verwendet werden zu können. Siehe XAML-Namespaces und Namespacezuordnung für WPF-XAML.
Anforderungen für eine benutzerdefinierte Klasse als XAML-Element
Um als Objektelement instanziiert werden zu können, muss Ihre Klasse die folgenden Anforderungen erfüllen:
Ihre benutzerdefinierte Klasse muss öffentlich sein und einen öffentlichen Standardkonstruktor (parameterlose) unterstützen. (Hinweise zu Strukturen finden Sie im folgenden Abschnitt.)
Ihre benutzerdefinierte Klasse darf keine geschachtelte Klasse sein. Geschachtelte Klassen und der "Punkt" in ihrer allgemeinen CLR-Verwendungssyntax beeinträchtigen andere WPF- und/oder XAML-Features wie angefügte Eigenschaften.
Zusätzlich zur Aktivierung der Objektelementsyntax ermöglicht die Objektdefinition auch eigenschaftselementsyntax für alle anderen öffentlichen Eigenschaften, die dieses Objekt als Werttyp verwenden. Dies liegt daran, dass das Objekt jetzt als Objektelement instanziiert werden kann und den Eigenschaftselementwert einer solchen Eigenschaft ausfüllen kann.
Strukturen
Strukturen, die Sie als benutzerdefinierte Typen definieren, können immer in XAML in WPF erstellt werden. Dies liegt daran, dass die CLR-Compiler implizit einen parameterlosen Konstruktor für eine Struktur erstellen, die alle Eigenschaftswerte auf ihre Standardwerte initialisiert. In einigen Fällen ist das Standardverhalten des Konstruktions- und/oder Objektelements für eine Struktur nicht wünschenswert. Dies kann daran liegen, dass die Struktur Werte ausfüllen und konzeptionell als Vereinigung funktionieren soll, wobei die enthaltenen Werte möglicherweise sich gegenseitig ausschließende Interpretationen haben und somit keine seiner Eigenschaften festgelegt werden kann. Ein WPF-Beispiel für eine solche Struktur ist GridLength. Im Allgemeinen sollten solche Strukturen einen Typkonverter implementieren, sodass die Werte in Attributform ausgedrückt werden können, indem Zeichenfolgenkonventionen verwendet werden, die die verschiedenen Interpretationen oder Modi der Werte der Struktur erstellen. Die Struktur sollte auch ein ähnliches Verhalten für die Codeerstellung über einen nicht parameterlosen Konstruktor verfügbar machen.
Anforderungen für Eigenschaften einer benutzerdefinierten Klasse als XAML-Attribute
Eigenschaften müssen auf einen Nachwerttyp (z. B. einen Grundtyp) verweisen oder eine Klasse für Typ verwenden, auf die entweder ein parameterloser Konstruktor oder ein dedizierter Typkonverter verfügt, auf den ein XAML-Prozessor zugreifen kann. In der CLR-XAML-Implementierung finden XAML-Prozessoren solche Konverter entweder durch die native Unterstützung von Sprachprimitiven oder durch die Anwendung eines TypeConverterAttribute auf einen Typ oder ein Mitglied in den zugrunde liegenden Typdefinitionen.
Alternativ kann die Eigenschaft auf einen abstrakten Klassentyp oder eine Schnittstelle verweisen. Bei abstrakten Klassen oder Schnittstellen erwartet die XAML-Analyse, dass der Eigenschaftswert mit konkreten Klasseninstanzen gefüllt werden muss, die die Schnittstelle implementieren, oder Instanzen von Typen, die von der abstrakten Klasse abgeleitet sind.
Eigenschaften können für eine abstrakte Klasse deklariert werden, können jedoch nur für konkrete Klassen festgelegt werden, die von der abstrakten Klasse abgeleitet werden. Dies liegt daran, dass das Erstellen des Objektelements für die Klasse überhaupt einen öffentlichen parameterlosen Konstruktor für die Klasse erfordert.
Attribute-Syntax für aktivierten TypeConverter
Wenn Sie einen dedizierten, attributierten Typkonverter auf Klassenebene bereitstellen, ermöglicht die angewendete Typkonvertierung Attributsyntax für jede Eigenschaft, die diesen Typ instanziieren muss. Ein Typkonverter aktiviert die Objektelementverwendung des Typs nicht; Nur das Vorhandensein eines parameterlosen Konstruktors für diesen Typ ermöglicht die Verwendung von Objektelementen. Daher sind Eigenschaften, die typkonverterfähig sind, in der Regel nicht in der Eigenschaftssyntax verwendbar, es sei denn, der Typ selbst unterstützt auch die Objektelementsyntax. Die Ausnahme besteht darin, dass Sie eine Eigenschaftselementsyntax angeben können, aber das Eigenschaftselement eine Zeichenfolge enthält. Diese Verwendung entspricht im Wesentlichen einer Attributsyntaxverwendung, und eine solche Verwendung ist nicht üblich, es sei denn, eine robustere Leerraumbehandlung des Attributwerts ist erforderlich. Im Folgenden sehen Sie beispielsweise eine Eigenschaftselementverwendung, die eine Zeichenfolge verwendet, und die Attributverwendungsäquivalent:
<Button>Hallo!
<Button.Language>
de-DE
</Button.Language>
</Button>
<Button Language="de-DE">Hallo!</Button>
Beispiele für Eigenschaften, bei denen attributsyntax zulässig ist, aber Eigenschaftselementsyntax, die ein Objektelement enthält, ist durch XAML nicht zulässig, sind verschiedene Eigenschaften, die den Cursor Typ übernehmen. Die Cursor Klasse verfügt über einen dedizierten Typkonverter CursorConverter, macht aber keinen parameterlosen Konstruktor verfügbar, sodass die Cursor Eigenschaft nur über Attributsyntax festgelegt werden kann, obwohl der tatsächliche Cursor Typ ein Verweistyp ist.
Per-Property Typkonverter
Alternativ kann die Eigenschaft selbst einen Typkonverter auf Eigenschaftsebene deklarieren. Dadurch wird eine "Minisprache" ermöglicht, die Objekte des Typs der Eigenschaft inline instanziiert, indem eingehende Zeichenfolgenwerte des Attributs als Eingabe für einen ConvertFrom Vorgang basierend auf dem entsprechenden Typ verarbeitet werden. In der Regel erfolgt dies, um einen Benutzerfreundlichkeits-Accessor bereitzustellen, und nicht als einzige Möglichkeit zum Aktivieren der Einstellung einer Eigenschaft in XAML. Es ist jedoch auch möglich, Typkonverter für Attribute zu verwenden, bei denen Sie vorhandene CLR-Typen verwenden möchten, die keinen parameterlosen Konstruktor oder einen Attributtypkonverter bereitstellen. Beispiele aus der WPF-API sind bestimmte Eigenschaften, die den CultureInfo Typ annehmen. In diesem Fall hat WPF den vorhandenen Microsoft .NET Framework-Typ CultureInfo verwendet, um Kompatibilitäts- und Migrationsszenarien zu verbessern, die in früheren Versionen von Frameworks verwendet wurden, aber der CultureInfo Typ hat die erforderliche Konstruktoren- oder Typtypkonvertierung nicht unterstützt, um direkt als XAML-Eigenschaftswert zu verwenden.
Wenn Sie eine Eigenschaft verfügbar machen, die eine XAML-Verwendung aufweist, insbesondere wenn Sie ein Steuerelementautor sind, sollten Sie diese Eigenschaft unbedingt mit einer Abhängigkeitseigenschaft sichern. Dies gilt insbesondere, wenn Sie die vorhandene Windows Presentation Foundation (WPF)-Implementierung des XAML-Prozessors verwenden, da Sie die Leistung mithilfe von DependencyProperty-Unterstützung verbessern können. Eine Abhängigkeitseigenschaft stellt Eigenschaftssystem-Funktionen für Ihre Eigenschaft bereit, die Benutzer von einer XAML-zugänglichen Eigenschaft erwarten. Dazu gehören Eigenschaften wie Animation, Datenbindung und Stilunterstützung. Weitere Informationen finden Sie unter Benutzerdefinierte Abhängigkeitseigenschaften und XAML-Lade- und Abhängigkeitseigenschaften.
Schreiben und Attributieren eines Typkonverters
Gelegentlich müssen Sie eine benutzerdefinierte TypeConverter abgeleitete Klasse schreiben, um eine Typkonvertierung für Ihren Eigenschaftstyp bereitzustellen. Anweisungen zum Ableiten von und Erstellen eines Typkonverters, der XAML-Verwendungen unterstützen kann, sowie zur Anwendung von TypeConverterAttribute, finden Sie unter TypeConverters und XAML.
Anforderungen für die XAML-Ereignishandlerattribut-Syntax bei Ereignissen einer benutzerdefinierten Klasse
Um als CLR-Ereignis verwendet werden zu können, muss das Ereignis als öffentliches Ereignis für eine Klasse verfügbar gemacht werden, die einen parameterlosen Konstruktor unterstützt, oder für eine abstrakte Klasse, auf die das Ereignis für abgeleitete Klassen zugreifen kann. Um bequem als routingfähiges Ereignis verwendet zu werden, sollte Ihr CLR-Ereignis explizite add
und remove
Methoden implementieren, die Handler für die CLR-Ereignissignatur hinzufügen und entfernen und diese Handler an die AddHandler und RemoveHandler methoden weiterleiten. Mit diesen Methoden werden die Handler zum Routingereignishandlerspeicher in der Instanz hinzugefügt oder entfernt, an die das Ereignis angefügt ist.
Hinweis
Es ist möglich, Handler direkt für Routingereignisse mithilfe von AddHandler zu registrieren und absichtlich kein CLR-Ereignis zu definieren, das das Routingereignis verfügbar macht. Dies wird im Allgemeinen nicht empfohlen, da das Ereignis keine XAML-Attributsyntax für das Anfügen von Handlern aktiviert, und die resultierende Klasse bietet eine weniger transparente XAML-Ansicht der Funktionen dieses Typs.
Eigenschaften von Auflistungen schreiben
Eigenschaften, die einen Auflistungstyp verwenden, weisen eine XAML-Syntax auf, mit der Sie Objekte angeben können, die der Auflistung hinzugefügt werden. Diese Syntax weist zwei wichtige Features auf.
Das Objekt, das das Auflistungsobjekt ist, muss nicht in der Objektelementsyntax angegeben werden. Das Vorhandensein dieses Sammlungstyps ist implizit, wenn Sie eine Eigenschaft in XAML angeben, die einen Sammlungstyp verwendet.
Untergeordnete Elemente der Auflistungseigenschaft im Markup werden verarbeitet, um der Sammlung hinzugefügt zu werden. Normalerweise erfolgt der Zugriff auf die Mitglieder einer Sammlung durch Listen-/Wörterbuchmethoden wie
Add
oder durch einen Indexer. Die XAML-Syntax unterstützt jedoch keine Methoden oder Indexer (Ausnahme: XAML 2009 kann Methoden unterstützen, die Verwendung von XAML 2009 schränkt jedoch die möglichen WPF-Verwendungen ein; siehe XAML 2009-Sprachfeatures). Sammlungen sind offensichtlich eine sehr häufige Anforderung zum Erstellen einer Struktur von Elementen, und Sie benötigen eine Möglichkeit, diese Auflistungen in deklarativem XAML aufzufüllen. Daher werden untergeordnete Elemente einer Auflistungseigenschaft verarbeitet, indem sie der Auflistung hinzugefügt werden, bei der es sich um den Eigenschaftstypwert der Auflistung handelt.
Die .NET Framework XAML Services-Implementierung und damit der WPF-XAML-Prozessor verwendet die folgende Definition für das, was eine Sammlungseigenschaft darstellt. Der Eigenschaftstyp der Eigenschaft muss eine der folgenden implementieren:
Implementiert IList.
Implementiert IDictionary.
Abgeleitet von Array (weitere Informationen zu Arrays in XAML finden Sie unter x:Array Markup Extension.)
IAddChild Implementiert (eine schnittstelle, die von WPF definiert wird).
Jeder dieser Typen in CLR verfügt über eine Add
Methode, die vom XAML-Prozessor zum Hinzufügen von Elementen zur zugrunde liegenden Auflistung beim Erstellen des Objektdiagramms verwendet wird.
Hinweis
Die generischen List
- und Dictionary
-Schnittstellen (IList<T> und IDictionary<TKey,TValue>) werden zur Erkennung von Sammlungen vom WPF-XAML-Prozessor nicht unterstützt. Sie können jedoch die List<T>-Klasse als Basisklasse verwenden, da sie IList direkt implementiert, oder Dictionary<TKey,TValue> als Basisklasse verwenden, da sie IDictionary direkt implementiert.
Wenn Sie eine Eigenschaft deklarieren, die eine Sammlung enthält, seien Sie vorsichtig, wie dieser Eigenschaftswert in neuen Instanzen des Typs initialisiert wird. Wenn Sie die Eigenschaft nicht als Abhängigkeitseigenschaft implementieren, reicht es aus, ein Feld zur Speicherung zu verwenden, das den Konstruktor für Sammlungstypen aufruft. Wenn Ihre Eigenschaft eine Abhängigkeitseigenschaft ist, müssen Sie die Sammlung möglicherweise als Teil des Standardkonstruktors initialisieren. Dies liegt daran, dass eine Abhängigkeitseigenschaft ihren Standardwert aus Metadaten bezieht, und Sie möchten normalerweise nicht, dass der Anfangswert einer Sammlungseigenschaft eine statische, geteilte Auflistung ist. Es sollte eine Sammlungsinstanz pro enthaltenden Typinstanz vorhanden sein. Weitere Informationen finden Sie unter Benutzerdefinierte Abhängigkeitseigenschaften.
Sie können einen benutzerdefinierten Sammlungstyp für Ihre Sammlungseigenschaft implementieren. Aufgrund der impliziten Sammlungseigenschaftsbehandlung muss der benutzerdefinierte Sammlungstyp keinen parameterlosen Konstruktor bereitstellen, um in XAML implizit verwendet werden zu können. Optional können Sie jedoch einen parameterlosen Konstruktor für den Sammlungstyp bereitstellen. Dies kann eine lohnende Praxis sein. Sofern Sie keinen parameterlosen Konstruktor bereitstellen, können Sie die Auflistung nicht explizit als Objektelement deklarieren. Einige Markupautoren ziehen möglicherweise eine explizite Sammlung aus stilistischen Gründen vor. Außerdem kann ein parameterloser Konstruktor die Initialisierungsanforderungen vereinfachen, wenn Sie neue Objekte erstellen, die den Sammlungstyp als Eigenschaftswert verwenden.
Deklarieren von XAML-Inhaltseigenschaften
Die XAML-Sprache definiert das Konzept einer XAML-Inhaltseigenschaft. Jede Klasse, die in der Objektsyntax verwendet werden kann, kann genau eine XAML-Inhaltseigenschaft aufweisen. Wenn Sie eine Eigenschaft als XAML-Inhaltseigenschaft für Ihre Klasse deklarieren möchten, wenden Sie die ContentPropertyAttribute Klasse als Teil der Klassendefinition an. Geben Sie den Namen der vorgesehenen XAML-Inhaltseigenschaft als Name im Attribut an. Die Eigenschaft wird als Zeichenfolge nach Namen angegeben, nicht als Spiegelungskonstrukt wie PropertyInfo.
Sie können eine Sammlungseigenschaft angeben, die die XAML-Inhaltseigenschaft sein soll. Dies führt zu einer Nutzung dieser Eigenschaft, bei der das Objektelement wenigstens ein untergeordnetes Element haben kann, ohne dass dazwischen Auflistungsobjektelemente oder Eigenschaftselement-Tags stehen. Diese Elemente werden dann als Wert für die XAML-Inhaltseigenschaft behandelt und der zugrunde liegenden Sammlung hinzugefügt.
Einige vorhandene XAML-Inhaltseigenschaften verwenden den Eigenschaftstyp von Object
. Dies ermöglicht eine XAML-Inhaltseigenschaft, die primitive Werte wie z. B. ein String und einen einzelnen Verweisobjektwert annehmen kann. Wenn Sie diesem Modell folgen, ist Ihr Typ sowohl für die Typbestimmung als auch für die Behandlung möglicher Typen verantwortlich. Der typische Grund für einen Object Inhaltstyp besteht darin, sowohl ein einfaches Mittel zum Hinzufügen von Objektinhalten als Zeichenfolge (die eine Standarddarstellungsbehandlung erhält) oder ein erweitertes Mittel zum Hinzufügen von Objektinhalten, die eine nicht standardmäßige Präsentation oder zusätzliche Daten angibt, zu unterstützen.
Serialisieren von XAML
Für bestimmte Szenarien, z. B. wenn Sie ein Steuerelement-Autor sind, sollten Sie sicherstellen, dass jede Objektdarstellung, die in XAML instanziiert werden kann, auch in ein entsprechendes XAML-Markup zurückserialisiert werden kann. Serialisierungsanforderungen werden in diesem Thema nicht beschrieben. Siehe Übersicht zur Erstellung von Steuerelementen und Elementstruktur und Serialisierung.
Siehe auch
.NET Desktop feedback