Delen via


XAML- en aangepaste klassen voor WPF

XAML zoals geïmplementeerd in CLR-frameworks (Common Language Runtime) biedt ondersteuning voor de mogelijkheid om een aangepaste klasse of structuur te definiëren in een COMMON Language Runtime-taal (CLR) en vervolgens toegang te krijgen tot die klasse met behulp van XAML-opmaak. U kunt een combinatie van wpF-gedefinieerde typen (Windows Presentation Foundation) en uw aangepaste typen in hetzelfde opmaakbestand gebruiken, meestal door de aangepaste typen toe te voegen aan een voorvoegsel voor de XAML-naamruimte. In dit onderwerp worden de vereisten besproken waaraan een aangepaste klasse moet voldoen om te kunnen worden gebruikt als een XAML-element.

Aangepaste klassen in toepassingen of assemblages

Aangepaste klassen die in XAML worden gebruikt, kunnen op twee verschillende manieren worden gedefinieerd: binnen de code-achter of andere code die de primaire WPF-toepassing (Windows Presentation Foundation) produceert, of als een klasse in een afzonderlijke assembly, zoals een uitvoerbaar bestand of DLL dat wordt gebruikt als een klassebibliotheek. Elk van deze benaderingen heeft specifieke voor- en nadelen.

  • Het voordeel van het maken van een klassebibliotheek is dat dergelijke aangepaste klassen kunnen worden gedeeld in veel verschillende mogelijke toepassingen. Een afzonderlijke bibliotheek maakt versiebeheerproblemen van toepassingen ook gemakkelijker te beheren en vereenvoudigt het maken van een klasse waarbij het beoogde klassegebruik zich als een hoofdelement op een XAML-pagina bevindt.

  • Het voordeel van het definiëren van de aangepaste klassen in de toepassing is dat deze techniek relatief licht is en de implementatie- en testproblemen minimaliseert die optreden wanneer u afzonderlijke assembly's introduceert buiten het uitvoerbare bestand van de hoofdtoepassing.

  • Ongeacht of deze zijn gedefinieerd in dezelfde of andere assembly, moeten aangepaste klassen worden toegewezen tussen CLR-naamruimte en XML-naamruimte om in XAML als elementen te kunnen worden gebruikt. Zie XAML-naamruimten en naamruimtetoewijzing voor WPF XAML.

Vereisten voor een aangepaste klasse als een XAML-element

Als u wilt kunnen worden geïnstantieerd als objectelement, moet uw klasse voldoen aan de volgende vereisten:

  • Uw aangepaste klasse moet openbaar zijn en ondersteuning bieden voor een openbare standaardconstructor (zonder parameters). (Zie de volgende sectie voor opmerkingen over structuren.)

  • Uw aangepaste klas mag geen geneste klas zijn. Geneste klassen en de 'punt' in hun algemene CLR-gebruiksyntaxis interfereren met andere WPF- en/of XAML-functies, zoals gekoppelde eigenschappen.

Naast het inschakelen van de syntaxis van objectelementen, maakt de objectdefinitie ook syntaxis van het eigenschapselement mogelijk voor andere openbare eigenschappen die dat object als waardetype gebruiken. Dit komt doordat het object nu geïnstantieerd kan worden als een objectelement en de waarde van een eigenschapselement van een dergelijke eigenschap kan invullen.

Structuren

Structuren die u definieert als aangepaste typen, kunnen altijd worden gebouwd in XAML in WPF. Dit komt doordat de CLR-compilers impliciet een parameterloze constructor maken voor een structuur die alle eigenschapswaarden initialiseert naar de standaardwaarden. In sommige gevallen is het standaard bouwgedrag en/of objectelementgebruik voor een structuur niet wenselijk. Dit kan komen doordat de structuur is bedoeld om waarden op te vullen en conceptueel te functioneren als een samenvoeging, waarbij de waarden die zijn opgenomen elkaar wederzijds uitsluiten en dus geen van de eigenschappen ervan zijn ingesteld. Een WPF-voorbeeld van een dergelijke structuur is GridLength. Over het algemeen moeten dergelijke structuren een typeconversieprogramma implementeren, zodat de waarden kunnen worden uitgedrukt in kenmerkvorm, met behulp van tekenreeksconventies die de verschillende interpretaties of modi van de waarden van de structuur maken. De structuur moet ook vergelijkbaar gedrag blootstellen voor codeconstructie via een niet-parameterloze constructor.

Vereisten voor eigenschappen van een aangepaste klasse als XAML-kenmerken

Eigenschappen moeten verwijzen naar een by-value-type (zoals een primitieve) of een klasse gebruiken voor het type dat een parameterloze constructor of een toegewezen typeconversieprogramma heeft waartoe een XAML-processor toegang heeft. In de CLR XAML-implementatie vinden XAML-processors dergelijke conversieprogramma's via inheemse ondersteuning voor taalprimitieven, of door toepassing van TypeConverterAttribute op een type of lid in definities van bestaande types.

De eigenschap kan ook verwijzen naar een abstract klassetype of een interface. Voor abstracte klassen of interfaces is de verwachting voor XAML-parsering dat de eigenschapswaarde moet worden gevuld met concrete klasse-exemplaren die de interface implementeren, of exemplaren van typen die zijn afgeleid van de abstracte klasse.

Eigenschappen kunnen worden gedeclareerd voor een abstracte klasse, maar kunnen alleen worden ingesteld op concrete klassen die zijn afgeleid van de abstracte klasse. Dit komt doordat het maken van het objectelement voor de klasse helemaal een openbare parameterloze constructor voor de klasse vereist.

Kenmerksyntaxis met TypeConverter ingeschakeld

Als u een speciaal, toegewijd typeconverter op klasseniveau opgeeft, maakt de toegepaste typeconversie attribuutsyntaxis mogelijk voor elke eigenschap die dat type moet instantiëren. Een typeconversieprogramma maakt het gebruik van objectelementen van het type niet mogelijk; alleen de aanwezigheid van een parameterloze constructor voor dat type maakt het gebruik van objectelementen mogelijk. Daarom zijn eigenschappen waarvoor typeconversieprogramma is ingeschakeld, over het algemeen niet bruikbaar in de syntaxis van de eigenschap, tenzij het type zelf ook de syntaxis van objectelementen ondersteunt. De uitzondering hierop is dat u een syntaxis van een eigenschapselement kunt opgeven, maar het eigenschapselement een tekenreeks bevat. Dat gebruik is in feite gelijk aan het gebruik van een kenmerksyntaxis en een dergelijk gebruik is niet gebruikelijk, tenzij er behoefte is aan robuustere verwerking van witruimte van de kenmerkwaarde. Bijvoorbeeld, het volgende is een voorbeeld van het gebruik van een eigenschapselement dat een tekenreeks aanneemt, en het equivalent daarvan in het gebruik van een attribuut:

<Button>Hallo!
  <Button.Language>
    de-DE
  </Button.Language>
</Button>
<Button Language="de-DE">Hallo!</Button>

Voorbeelden van eigenschappen waarbij kenmerksyntaxis is toegestaan, maar syntaxis van het eigenschapselement dat een objectelement bevat, is niet toegestaan via XAML zijn verschillende eigenschappen die het Cursor type aannemen. De Cursor klasse heeft een toegewezen typeconversieprogramma CursorConverter, maar biedt geen constructor zonder parameters, zodat de Cursor eigenschap alleen kan worden ingesteld via de kenmerksyntaxis, ook al is het werkelijke Cursor type een verwijzingstype.

conversieprogramma's voor Per-Property

De eigenschap zelf kan ook een type converter declareren op eigenschappenniveau. Hierdoor kan een "mini-taal" worden gemaakt waarmee objecten van het type van de eigenschap inline worden geïnstantieerd, door binnenkomende tekenreekswaarden van het kenmerk te gebruiken als invoer voor een ConvertFrom-bewerking op basis van het geschikte type. Dit wordt meestal gedaan om een handige toegangsfunctie te bieden en niet als de enige manier om het instellen van een eigenschap in XAML mogelijk te maken. Het is echter ook mogelijk om typeconversieprogramma's te gebruiken voor kenmerken waarbij u bestaande CLR-typen wilt gebruiken die geen parameterloze constructor of een toegeschreven typeconversieprogramma leveren. Voorbeelden van de WPF-API zijn bepaalde eigenschappen die het CultureInfo type aannemen. In dit geval heeft WPF het bestaande Microsoft .NET Framework-type CultureInfo gebruikt om de compatibiliteits- en migratiescenario's die in eerdere versies van frameworks zijn gebruikt, beter aan te pakken, maar het CultureInfo typetype heeft de benodigde constructors of typeconversie op typeniveau niet ondersteund om rechtstreeks als een XAML-eigenschapswaarde te kunnen worden gebruikt.

Wanneer u een eigenschap beschikbaar maakt die een XAML-gebruik heeft, met name als u een auteur van een besturingselement bent, moet u er sterk voor overwegen deze eigenschap te voorzien van een afhankelijkheidseigenschap. Dit geldt met name als u de bestaande WPF-implementatie (Windows Presentation Foundation) van de XAML-processor gebruikt, omdat u de prestaties kunt verbeteren met behulp van DependencyProperty back-up. Een afhankelijkheidseigenschap stelt eigenschappensysteemfuncties beschikbaar voor uw eigenschap die gebruikers verwachten voor een XAML-toegankelijke eigenschap. Dit omvat functies zoals animatie, gegevensbinding en stijlondersteuning. Zie Eigenschappen van aangepaste afhankelijkheden en XAML-eigenschappen voor laden en afhankelijkheid voor meer informatie.

Een typeconversieprogramma schrijven en toewijzen

Af en toe moet u een aangepaste TypeConverter afgeleide klasse schrijven om typeconversie voor uw eigenschapstype te bieden. Zie TypeConverterAttribute voor instructies over het afleiden en maken van een typeconversieprogramma dat XAML-gebruik kan ondersteunen en hoe u deze kunt toepassen.

Vereisten voor de syntaxis van XAML-gebeurtenishandlerkenmerken voor gebeurtenissen van een aangepaste klasse

Als u een CLR-gebeurtenis wilt gebruiken, moet de gebeurtenis worden weergegeven als een openbare gebeurtenis op een klasse die ondersteuning biedt voor een parameterloze constructor of op een abstracte klasse waar de gebeurtenis kan worden geopend op afgeleide klassen. Om handig te kunnen worden gebruikt als een gerouteerde gebeurtenis moet uw CLR-gebeurtenis expliciete add en remove methoden implementeren om handlers voor de signatuur van de CLR-gebeurtenis toe te voegen en te verwijderen, en deze handlers door te sturen naar de AddHandler en RemoveHandler methoden. Met deze methoden worden de handlers toegevoegd aan of verwijderd uit het gerouteerde gebeurtenishandlerarchief op het exemplaar waaraan de gebeurtenis is gekoppeld.

Opmerking

Het is mogelijk om handlers rechtstreeks te registreren voor gerouteerde gebeurtenissen met behulp van AddHandleren om bewust geen CLR-gebeurtenis te definiëren die de gerouteerde gebeurtenis blootstelt. Dit wordt over het algemeen niet aanbevolen omdat de gebeurtenis de syntaxis van het XAML-kenmerk niet inschakelt voor het koppelen van handlers en uw resulterende klasse een minder transparante XAML-weergave van de mogelijkheden van dat type biedt.

Eigenschappen van verzameling schrijven

Eigenschappen die een verzamelingstype gebruiken, hebben een XAML-syntaxis waarmee u objecten kunt opgeven die aan de verzameling worden toegevoegd. Deze syntaxis heeft twee belangrijke functies.

  • Het object dat het verzamelingsobject is, hoeft niet te worden opgegeven in de syntaxis van het objectelement. De aanwezigheid van dat verzamelingstype is impliciet wanneer u een eigenschap opgeeft in XAML die een verzamelingstype gebruikt.

  • Kindelementen van de collectie-eigenschap in markeringen worden verwerkt om lid te worden van de collectie. Normaal gesproken wordt de codetoegang tot de leden van een verzameling uitgevoerd via lijst-/woordenlijstmethoden zoals Add, of via een indexeerfunctie. Maar XAML-syntaxis biedt geen ondersteuning voor methoden of indexeerfuncties (uitzondering: XAML 2009 kan methoden ondersteunen, maar het gebruik van XAML 2009 beperkt het mogelijke WPF-gebruik; zie XAML 2009-taalfuncties). Verzamelingen zijn duidelijk een zeer algemene vereiste voor het bouwen van een structuur met elementen en u hebt een manier nodig om deze verzamelingen in declaratieve XAML te vullen. Onderliggende elementen van een verzamelingseigenschap worden daarom verwerkt door ze toe te voegen aan de verzameling die de waarde van het eigenschapstype van de verzameling is.

De .NET Framework XAML Services-implementatie en daarom gebruikt de WPF XAML-processor de volgende definitie voor wat een verzamelingseigenschap vormt. Het eigenschapstype van de eigenschap moet een van de volgende implementeren:

Elk van deze typen in CLR heeft een Add methode die wordt gebruikt door de XAML-processor om items toe te voegen aan de onderliggende verzameling bij het maken van de objectgrafiek.

Opmerking

De algemene ListDictionary interfaces (IList<T> en IDictionary<TKey,TValue>) worden niet ondersteund voor verzamelingsdetectie door de WPF XAML-processor. U kunt de List<T> klasse echter gebruiken als basisklasse, omdat deze IList rechtstreeks implementeert of Dictionary<TKey,TValue> als basisklasse gebruiken, omdat deze IDictionary rechtstreeks implementeert.

Wanneer u een eigenschap declareert die een verzameling gebruikt, moet u voorzichtig zijn met hoe die eigenschapswaarde wordt geïnitialiseerd in nieuwe exemplaren van het type. Als u de eigenschap niet als een afhankelijkheidseigenschap implementeert, is het voldoende dat de eigenschap gebruik maakt van een ondersteunend veld dat de constructor van het type verzameling aanroept. Als uw eigenschap een afhankelijkheidseigenschap is, moet u mogelijk de verzamelingseigenschap initialiseren als onderdeel van de standaardtypeconstructor. Dit komt doordat een afhankelijkheidseigenschap de standaardwaarde van metagegevens gebruikt en u doorgaans niet wilt dat de oorspronkelijke waarde van een verzamelingseigenschap een statische, gedeelde verzameling is. Er moet een verzamelingsvoorbeeld per elke omhullende type-instantie zijn. Zie Aangepaste afhankelijkheidseigenschappenvoor meer informatie.

U kunt een aangepast verzamelingstype implementeren voor uw verzamelingseigenschap. Vanwege een impliciete verzamelingseigenschapsbehandeling hoeft het aangepaste verzamelingstype geen parameterloze constructor te bieden om impliciet in XAML te kunnen worden gebruikt. U kunt echter desgewenst een parameterloze constructor opgeven voor het verzamelingstype. Dit kan een waardevolle oefening zijn. Tenzij u een parameterloze constructor opgeeft, kunt u de verzameling niet expliciet declareren als objectelement. Sommige auteurs van opmaaktaal geven er mogelijk de voorkeur aan om de expliciete verzameling als een kwestie van opmaakstijl te beschouwen. Bovendien kan een constructor zonder parameters de initialisatievereisten vereenvoudigen wanneer u nieuwe objecten maakt die uw verzamelingstype als eigenschapswaarde gebruiken.

XAML-inhoudseigenschappen declareren

De XAML-taal definieert het concept van een XAML-inhoudseigenschap. Elke klasse die kan worden gebruikt in de objectsyntaxis, kan precies één XAML-inhoudseigenschap hebben. Als u een eigenschap wilt declareren als de inhoudseigenschap XAML voor uw klasse, past u het ContentPropertyAttribute toe als onderdeel van de klassedefinitie. Geef de naam op van de beoogde XAML-inhoudseigenschap bij het Name kenmerk. De eigenschap wordt opgegeven als een tekenreeks op naam, niet als een weerspiegelingsconstructie zoals PropertyInfo.

U kunt een verzamelingseigenschap opgeven als de inhoudseigenschap XAML. Dit resulteert in een gebruik voor die eigenschap, waarbij het objectelement een of meer onderliggende elementen kan hebben, zonder tussenliggende objectelementen of tags voor eigenschapselementen. Deze elementen worden vervolgens behandeld als de waarde voor de inhoudseigenschap XAML en toegevoegd aan het exemplaar van de ondersteunende verzameling.

Sommige bestaande XAML-inhoudseigenschappen gebruiken het eigenschapstype van Object. Hierdoor kan een XAML-inhoudseigenschap worden gebruikt die primitieve waarden kan aannemen, zoals een String en één referentieobjectwaarde. Als u dit model volgt, is uw type verantwoordelijk voor typebepaling en de verwerking van mogelijke typen. De gebruikelijke reden voor een Object inhoudstype is het ondersteunen van zowel een eenvoudige manier om objectinhoud toe te voegen als een tekenreeks (die een standaardpresentatiebehandeling ontvangt) of een geavanceerde manier om objectinhoud toe te voegen waarmee een niet-standaardpresentatie of aanvullende gegevens worden opgegeven.

XAML serialiseren

Voor bepaalde scenario's, zoals als u een auteur van een besturingselement bent, wilt u er ook voor zorgen dat elke objectweergave die kan worden geïnstantieerd in XAML, ook kan worden geserialiseerd naar equivalente XAML-markeringen. Serialisatievereisten worden niet beschreven in dit onderwerp. Zie Overzicht van besturingselementen en elementstructuur en serialisatie.

Zie ook