WPF XAML-naamscopen
XAML-naamscopen zijn een concept dat objecten identificeert die zijn gedefinieerd in XAML. De namen in een XAML-naamscoop kunnen worden gebruikt om relaties tot stand te brengen tussen de door XAML gedefinieerde namen van objecten en hun exemplaar-equivalenten in een objectstructuur. Normaal gesproken worden XAML-naamscopen in door WPF beheerde code gemaakt bij het laden van de afzonderlijke XAML-paginawortels voor een XAML-toepassing. XAML-naamscopen als het programmeerobject worden gedefinieerd door de INameScope interface en worden ook geïmplementeerd door de praktische klasse NameScope.
Namescopes in geladen XAML-toepassingen
In een bredere programmeer- of computerwetenschapcontext bevatten programmeerconcepten vaak het principe van een unieke id of naam die kan worden gebruikt voor toegang tot een object. Voor systemen die id's of namen gebruiken, definieert de naamscoop de grenzen waarbinnen een proces of techniek zoekt als een object van die naam wordt aangevraagd, of de grenzen waarbij uniekheid van identificatienamen wordt afgedwongen. Deze algemene principes gelden voor XAML-naamscopen. In WPF worden XAML-naamscopen gemaakt op het hoofdelement voor een XAML-pagina wanneer de pagina wordt geladen. Elke naam die is opgegeven op de XAML-pagina beginnend bij de paginawortel, wordt toegevoegd aan een passende XAML-naamscope.
In WPF XAML bepalen elementen die algemene hoofdelementen zijn (zoals Pageen Window) altijd een XAML-naamscoop. Als een element zoals FrameworkElement of FrameworkContentElement het rootelement van de pagina in de markup is, voegt een XAML-processor impliciet een Page-rootelement toe, zodat de Page een werkende XAML-naamscope kan bieden.
Notitie
WPF-buildacties maken een XAML-naamscoop voor een XAML-productie, zelfs als er geen Name
of x:Name
kenmerken zijn gedefinieerd op elementen in de XAML-markering.
Als u dezelfde naam twee keer probeert te gebruiken in een XAML-naamscoop, wordt er een uitzondering gegenereerd. Voor WPF XAML met code-behind dat deel uitmaakt van een gecompileerde toepassing, wordt de uitzondering gegenereerd door WPF-buildacties tijdens de build, wanneer de gegenereerde klasse voor de pagina tijdens de initiële markeringscompilatie wordt gemaakt. Voor XAML die niet is gecompileerd door een buildactie, kunnen uitzonderingen met betrekking tot XAML-naamscoopproblemen optreden wanneer de XAML wordt geladen. XAML-ontwerpers kunnen tijdens het ontwerpen ook XAML-naamscoopproblemen verwachten.
Objecten toevoegen aan runtime-objectstructuren
Het moment dat XAML wordt geparseerd, vertegenwoordigt het tijdstip waarop een WPF XAML-naamscoop wordt gemaakt en gedefinieerd. Als u op een bepaald moment een object toevoegt aan een objectboom nadat de XAML die deze boom heeft geproduceerd is geparseerd, worden de waarden Name
of x:Name
op het nieuwe object niet automatisch bijgewerkt in de XAML-naamscope. Als u een naam voor een object wilt toevoegen aan een WPF XAML-naamscoop nadat XAML is geladen, moet u de juiste implementatie van RegisterName aanroepen op het object dat de XAML-naamscoop definieert. Dit is doorgaans de hoofdmap van de XAML-pagina. Als de naam niet is geregistreerd, kan er niet naar het toegevoegde object worden verwezen via methoden zoals FindNameen kunt u die naam niet gebruiken voor animatie-targeting.
Het meest voorkomende scenario voor toepassingsontwikkelaars is dat u RegisterName gebruikt om namen te registreren in de XAML-naamscoop in de huidige hoofdmap van de pagina. RegisterName maakt deel uit van een belangrijk scenario voor storyboards die gericht zijn op objecten voor animaties. Zie Storyboards Overviewvoor meer informatie.
Als u RegisterName aanroept op een ander object dan het object dat de XAML-naamscoop definieert, wordt de naam nog steeds geregistreerd bij de XAML-naamscoop waarin het aanroepende object wordt bewaard, alsof u RegisterName had aangeroepen op het XAML-naamscoopdefinitieobject.
XAML-naamscopen in Code
U kunt XAML-naamscopen maken en vervolgens gebruiken in code. De API's en de concepten die betrokken zijn bij het maken van XAML-naamscoop zijn hetzelfde, zelfs voor een puur codegebruik, omdat de XAML-processor voor WPF deze API's en concepten gebruikt wanneer XAML zelf wordt verwerkt. De concepten en API bestaan voornamelijk om objecten te vinden op naam binnen een objectstructuur die doorgaans gedeeltelijk of volledig in XAML is gedefinieerd.
Voor toepassingen die programmatisch zijn gemaakt en niet van geladen XAML zijn afgeleid, moet het object dat een XAML-naamscoop definieert, INameScopeimplementeren, of moet het een afgeleide klasse van FrameworkElement of FrameworkContentElement zijn om het maken van een XAML-naamscoop op deze exemplaren te ondersteunen.
Voor elk element dat niet door een XAML-processor wordt geladen en verwerkt, wordt de XAML-naamscoop voor het object niet standaard gemaakt of geïnitialiseerd. U moet expliciet een nieuwe XAML-naamscoop maken voor elk object waarvoor u namen later wilt registreren. Als u een XAML-naamscoop wilt maken, roept u de statische SetNameScope methode aan. Geef het object op dat eigenaar is van de parameter dependencyObject
en een nieuwe NameScope constructor-aanroep als de parameter value
.
Als het object dat is opgegeven als dependencyObject
voor SetNameScope geen INameScope-implementatie is, FrameworkElement of FrameworkContentElement, heeft het aanroepen van RegisterName op onderliggende elementen geen effect. Als u de nieuwe XAML-naamscope niet expliciet maakt, zullen aanroepen van RegisterName een uitzondering veroorzaken.
Zie Een naambereik definiërenvoor een voorbeeld van het gebruik van XAML-naamscope-API's in code.
XAML-naamscopen in stijlen en sjablonen
Stijlen en sjablonen in WPF bieden de mogelijkheid om inhoud op een eenvoudige manier opnieuw te gebruiken en opnieuw toe te past. Stijlen en sjablonen kunnen echter ook elementen bevatten met XAML-namen die zijn gedefinieerd op sjabloonniveau. Dezelfde sjabloon kan meerdere keren op een pagina worden gebruikt. Daarom definiëren stijlen en sjablonen beide hun eigen XAML-naambereiken, onafhankelijk van de locatie in een objectstructuur waar de stijl of sjabloon wordt toegepast.
Bekijk het volgende voorbeeld:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<Page.Resources>
<ControlTemplate x:Key="MyButtonTemplate" TargetType="{x:Type Button}">
<Border BorderBrush="Red" Name="TheBorder" BorderThickness="2">
<ContentPresenter/>
</Border>
</ControlTemplate>
</Page.Resources>
<StackPanel>
<Button Template="{StaticResource MyButtonTemplate}">My first button</Button>
<Button Template="{StaticResource MyButtonTemplate}">My second button</Button>
</StackPanel>
</Page>
Hier wordt dezelfde sjabloon toegepast op twee verschillende knoppen. Als sjablonen geen discrete XAML-naamscopen hebben, zou de TheBorder
naam die in de sjabloon wordt gebruikt, een naamconflict veroorzaken in de XAML-naamscoop. Elke instantie van de sjabloon heeft een eigen XAML-naamscoop, dus in dit voorbeeld bevat elke geïnstantieerde XAML-naamscoop van elke geïnstantieerde sjabloon precies één naam.
Stijlen definiëren ook hun eigen XAML-naamscoop, meestal zodat delen van storyboards bepaalde namen kunnen hebben toegewezen. Met deze namen kunt u specifieke functies beheren die gericht zijn op elementen van die naam, zelfs als de sjabloon opnieuw is gedefinieerd als onderdeel van de aanpassing van het bedieningselement.
Vanwege de afzonderlijke XAML-naamscopen is het zoeken naar benoemde elementen in een sjabloon moeilijker dan het vinden van een niet-sjabloon benoemd element op een pagina. U moet eerst de toegepaste sjabloon bepalen door de Template eigenschapswaarde op te halen van het besturingselement waarop de sjabloon wordt toegepast. Vervolgens roept u de sjabloonversie van FindNameaan, waarbij u het besturingselement doorgeeft waar de sjabloon is toegepast als de tweede parameter.
Als u een auteur van een besturingselement bent en u een conventie genereert waarbij een bepaald benoemd element in een toegepaste sjabloon het doel is voor een gedrag dat door het besturingselement zelf wordt gedefinieerd, kunt u de GetTemplateChild methode gebruiken vanuit uw implementatiecode voor besturingselementen. De methode GetTemplateChild is beveiligd, zodat alleen de auteur van het besturingselement toegang tot deze methode heeft.
Als u vanuit een sjabloon werkt en naar de XAML-naamscoop moet gaan waar de sjabloon wordt toegepast, haalt u de waarde van TemplatedParentop en roept u FindName daar aan. Een voorbeeld van het werken binnen de sjabloon is als u de implementatie van de gebeurtenis-handler schrijft waarbij de gebeurtenis wordt gegenereerd vanuit een element in een toegepaste sjabloon.
XAML-naamscopen en naamgerelateerde API's
FrameworkElement heeft methoden voor FindName, RegisterName en UnregisterName. Als het object waarop u deze methoden aanroept zelf een XAML-naamscope heeft, worden de methoden binnen de relevante XAML-naamscope aangeroepen. Anders wordt het bovenliggende element gecontroleerd om te zien of het eigenaar is van een XAML-naamscoop en dit proces wordt recursief voortgezet totdat een XAML-naamscoop wordt gevonden (vanwege het gedrag van de XAML-processor is de aanwezigheid van een XAML-naamscoop bij de wortel gegarandeerd). FrameworkContentElement heeft vergelijkbaar gedrag, met uitzondering dat er geen FrameworkContentElement ooit een XAML-naamscoop zal hebben. De methoden bestaan op FrameworkContentElement, waarmee de aanroepen uiteindelijk naar een bovenliggend element FrameworkElement kunnen worden doorgestuurd.
SetNameScope wordt gebruikt om een nieuwe XAML-naamscoop toe te wijzen aan een bestaand object. U kunt SetNameScope meer dan één keer aanroepen om de XAML-naamscoop opnieuw in te stellen of te wissen, maar dat is geen gemeenschappelijk gebruik. Ook wordt GetNameScope doorgaans niet gebruikt vanuit code.
XAML Namescope-implementaties
De volgende klassen implementeren INameScope rechtstreeks:
ResourceDictionary maakt geen gebruik van XAML-namen of -naamscopen ; in plaats daarvan worden sleutels gebruikt, omdat het een woordenlijst-implementatie is. De enige reden waarom ResourceDictionaryINameScope implementeert, is zodat het uitzonderingen kan maken voor gebruikerscode die het onderscheid verduidelijkt tussen een echte XAML-naamscope en hoe een ResourceDictionary sleutels verwerkt, en om ervoor te zorgen dat XAML-naamscopes niet worden toegepast op een ResourceDictionary door bovenliggende elementen.
FrameworkTemplate en Style implementeren INameScope via expliciete interfacedefinities. Met de expliciete implementaties kunnen deze XAML-naamscopen zich conventioneel gedragen wanneer ze worden geopend via de INameScope-interface. Dit is de manier waarop XAML-naamscopen worden gecommuniceerd door interne WPF-processen. Maar de expliciete interfacedefinities maken geen deel uit van het conventionele API-oppervlak van FrameworkTemplate en Style, omdat u zelden de INameScope methoden op FrameworkTemplate en Style rechtstreeks hoeft aan te roepen en in plaats daarvan andere API's zoals GetTemplateChildgebruikt.
De volgende klassen definiëren hun eigen XAML-naamscoop, door de System.Windows.NameScope helperklasse te gebruiken en verbinding te maken met de XAML-naamscoop-implementatie via de gekoppelde eigenschap NameScope.NameScope:
Zie ook
.NET Desktop feedback