WPF XAML-namnrymder
XAML-namnskop är ett begrepp som identifierar objekt som definieras i XAML. Namnen i ett XAML-namnskop kan användas för att upprätta relationer mellan de XAML-definierade namnen på objekt och deras instansmotsvarigheter i ett objektträd. Vanligtvis skapas XAML-namnområden i kod som hanteras av WPF när de enskilda XAML-sidans rötter läses in för ett XAML-program. XAML-namnskop som programmeringsobjekt definieras av INameScope-gränssnittet och implementeras också av den praktiska klassen NameScope.
Namescopes i laddade XAML-applikationer
I ett bredare programmerings- eller datavetenskapssammanhang omfattar programmeringsbegrepp ofta principen om en unik identifierare eller ett namn som kan användas för att komma åt ett objekt. För system som använder identifierare eller namn definierar namnskopet de gränser inom vilka en process eller teknik söker om ett objekt med det namnet begärs eller gränserna där unika identifieringsnamn framtvingas. Dessa allmänna principer gäller för XAML-namnskop. I WPF skapas XAML-namnskop på rotelementet för en XAML-sida när sidan läses in. Varje namn som anges på XAML-sidan som börjar vid sidroten läggs till i ett relevant XAML-namnskop.
I WPF XAML styr element som är vanliga rotelement (till exempel Pageoch Window) alltid ett XAML-namnskop. Om ett element som FrameworkElement eller FrameworkContentElement är rotelementet på sidan i markering lägger en XAML-processor till en Page rot implicit så att Page kan tillhandahålla ett fungerande XAML-namnskop.
Notera
WPF-byggåtgärder skapar ett XAML-namnskop för en XAML-produktion även om inga Name
- eller x:Name
attribut definieras för alla element i XAML-markering.
Om du försöker använda samma namn två gånger i ett XAML-namnskop utlöses ett undantag. För WPF XAML som har bakomliggande kod och ingår i ett kompilerat program, genereras undantaget av WPF-byggåtgärder när du skapar den genererade klassen för sidan under den initiala kompileringen av markup. För XAML som inte är markup-kompilerad av någon byggåtgärd kan undantag som relaterar till problem med XAML-namnscope uppstå när XAML läses in. XAML-utvecklare kan också förutse problem med XAML-namnområden under designfasen.
Lägga till objekt i körningsobjektträd
Det ögonblick då XAML parsas representerar det ögonblick då ett WPF XAML-namnskop skapas och definieras. Om du lägger till ett objekt i ett objektträd vid en tidpunkt efter att XAML som skapade trädet parsades, uppdaterar inte ett Name
- eller x:Name
-värde på det nya objektet automatiskt informationen i ett XAML-namnskop. Om du vill lägga till ett namn för ett objekt i ett WPF XAML-namnskop när XAML har lästs in måste du anropa lämplig implementering av RegisterName på objektet som definierar XAML-namnskopet, som vanligtvis är XAML-sidroten. Om namnet inte är registrerat kan det tillagda objektet inte refereras med namn via metoder som FindName, och du kan inte använda det namnet för animeringsmål.
Det vanligaste scenariot för programutvecklare är att du använder RegisterName för att registrera namn i XAML-namnskopet på den aktuella roten på sidan. RegisterName är en del av ett viktigt scenario för storyboards som riktar in sig på objekt för animeringar. Mer information finns i Storyboards-översikten.
Om du anropar RegisterName på ett annat objekt än det objekt som definierar XAML-namnskopet är namnet fortfarande registrerat i XAML-namnskopet som det anropande objektet finns i, som om du hade anropat RegisterName på XAML-namnskopets definitionsobjekt.
XAML-namnskop i kod
Du kan skapa och sedan använda XAML-namnskop i kod. API:erna och begreppen som ingår i skapandet av XAML-namnskop är desamma även för en ren kodanvändning, eftersom XAML-processorn för WPF använder dessa API:er och begrepp när den bearbetar själva XAML. Begreppen och API:et finns främst för att kunna hitta objekt efter namn i ett objektträd som vanligtvis definieras delvis eller helt i XAML.
För program som skapas programmatiskt och inte från inläst XAML måste objektet som definierar ett XAML-namnskop implementera INameScope, eller vara en FrameworkElement- eller FrameworkContentElement härledd klass, för att kunna skapa ett XAML-namnskop på dess instanser.
För alla element som inte läses in och bearbetas av en XAML-processor skapas eller initieras inte XAML-namnskopet för objektet som standard. Du måste uttryckligen skapa ett nytt XAML-namnskop för alla objekt som du tänker registrera namn i senare. Om du vill skapa ett XAML-namnskop anropar du metoden static SetNameScope. Ange det objekt som ska äga det som parametern dependencyObject
och ett nytt NameScope konstruktoranrop som value
parameter.
Om objektet som tillhandahålls som dependencyObject
för SetNameScope inte är en INameScope implementering, FrameworkElement eller FrameworkContentElement, har det ingen effekt att anropa RegisterName på underordnade element. Om du inte skapar det nya XAML-namnskopet explicit skapar anrop till RegisterName ett undantag.
Ett exempel på hur du använder XAML-namnscope-API:er i kod finns i Definiera ett namnområde.
XAML-namnområden i format och mallar
Format och mallarna i WPF ger möjlighet att återanvända och tillämpa innehåll på nytt på ett enkelt sätt. Formatmallar och mallar kan dock även innehålla element med XAML-namn som definierats på mallnivå. Samma mall kan användas flera gånger på en sida. Därför definierar både formatmallar och mallar sina egna XAML-namnskop, oberoende av vilken plats i ett objektträd där formatmallen eller mallen används.
Tänk på följande exempel:
<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>
Här tillämpas samma mall på två olika knappar. Om mallarna inte hade diskreta XAML-namnskop skulle det TheBorder
namn som används i mallen orsaka en namnkollision i XAML-namnskopet. Varje instansiering av mallen har ett eget XAML-namnskop, så i det här exemplet skulle varje instansierad malls XAML-namnskop innehålla exakt ett namn.
Formatmallar definierar också sitt eget XAML-namnskop, främst så att delar av storyboards kan tilldelas specifika namn. Dessa namn aktiverar kontrollspecifika beteenden som kommer att rikta in sig på element i det namnet, även om mallen har definierats om som en del av kontrollanpassningen.
På grund av de separata XAML-namnskopen är det svårare att hitta namngivna element i en mall än att hitta ett icke-mallat namngivet element på en sida. Du måste först fastställa den tillämpade mallen genom att hämta Template egenskapsvärdet för kontrollen där mallen används. Sedan anropar du mallversionen av FindNameoch skickar kontrollen där mallen tillämpades som den andra parametern.
Om du är en kontrollförfattare och genererar en konvention där ett visst namngivet element i en tillämpad mall är målet för ett beteende som definieras av själva kontrollen kan du använda metoden GetTemplateChild från din kontrollimplementeringskod. Metoden GetTemplateChild är skyddad, så endast kontrollförfattaren har åtkomst till den.
Om du arbetar inifrån en mall och behöver komma till XAML-namnskopet där mallen används hämtar du värdet för TemplatedParentoch anropar sedan FindName där. Ett exempel på hur du arbetar i mallen är om du skriver implementeringen av händelsehanteraren där händelsen hämtas från ett element i en tillämpad mall.
XAML-namnskop och namnrelaterade API:er
FrameworkElement har metoderna FindName, RegisterName och UnregisterName. Om objektet som du anropar dessa metoder på äger ett XAML-namnskop anropar metoderna metoderna för det relevanta XAML-namnskopet. Annars kontrolleras det överordnade elementet för att se om det äger ett XAML-namnskop, och den här processen fortsätter rekursivt tills ett XAML-namnskop hittas (på grund av XAML-processorbeteendet är det garanterat ett XAML-namnskop i roten). FrameworkContentElement har liknande beteenden, med undantag för att ingen FrameworkContentElement någonsin kommer att äga ett XAML-namnskop. Metoderna finns på FrameworkContentElement så att anropen så småningom kan vidarebefordras till ett FrameworkElement överordnat element.
SetNameScope används för att mappa ett nytt XAML-namnskop till ett befintligt objekt. Du kan anropa SetNameScope mer än en gång för att återställa eller rensa XAML-namnskopet, men det är inte en vanlig användning. Dessutom används GetNameScope vanligtvis inte i kod.
Implementeringar av XAML-namnskop
Följande klasser implementerar INameScope direkt:
ResourceDictionary använder inte XAML-namn eller namnskop ; den använder nycklar i stället, eftersom det är en ordlisteimplementering. Den enda anledningen till att ResourceDictionary implementerar INameScope är att det kan generera undantag till användarkod som hjälper till att klargöra skillnaden mellan ett sant XAML-namnskop och hur en ResourceDictionary hanterar nycklar, och även för att säkerställa att XAML-namnskop inte tillämpas på en ResourceDictionary av överordnade element.
FrameworkTemplate och Style implementera INameScope via explicita gränssnittsdefinitioner. Med de uttryckliga implementeringarna kan dessa XAML-namnskop uppträda konventionellt när de används via INameScope-gränssnittet, vilket är på vilket sätt XAML-namnskop kommuniceras av interna WPF-processer. Men de explicita gränssnittsdefinitionerna är inte en del av den konventionella API-ytan för FrameworkTemplate och Style, eftersom du sällan behöver anropa INameScope-metoderna på FrameworkTemplate och Style direkt, utan i stället använder andra API:er som GetTemplateChild.
Följande klasser definierar sitt eget XAML-namnskop genom att använda hjälpklassen System.Windows.NameScope och ansluta till dess XAML-namnskopimplementering via den NameScope.NameScope anslutna egenskapen:
Se även
.NET Desktop feedback