Dela via


Översikt över XAML-resurser

En resurs är ett objekt som kan återanvändas på olika platser i din app. Exempel på resurser är penslar och formatmallar. Den här översikten beskriver hur du använder resurser i XAML (Extensible Application Markup Language). Du kan också skapa och komma åt resurser med hjälp av kod.

Anmärkning

XAML-resurser som beskrivs i den här artikeln skiljer sig från appresurser, som vanligtvis är filer som läggs till i en app, till exempel innehåll, data eller inbäddade filer.

Använda resurser i XAML

I följande exempel definieras en SolidColorBrush som en resurs på rotelementet på en sida. Exemplet refererar sedan till resursen och använder den för att ange egenskaper för flera underordnade element, inklusive en Ellipse, en TextBlockoch en Button.

<Window x:Class="resources.ResExample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="ResExample" Height="400" Width="300">
    <Window.Resources>
        <SolidColorBrush x:Key="MyBrush" Color="#05E0E9"/>
        <Style TargetType="Border">
            <Setter Property="Background" Value="#4E1A3D" />
            <Setter Property="BorderThickness" Value="5" />
            <Setter Property="BorderBrush">
                <Setter.Value>
                    <LinearGradientBrush>
                        <GradientStop Offset="0.0" Color="#4E1A3D"/>
                        <GradientStop Offset="1.0" Color="Salmon"/>
                    </LinearGradientBrush>
                </Setter.Value>
            </Setter>
        </Style>
        <Style TargetType="TextBlock" x:Key="TitleText">
            <Setter Property="FontSize" Value="18"/>
            <Setter Property="Foreground" Value="#4E87D4"/>
            <Setter Property="FontFamily" Value="Trebuchet MS"/>
            <Setter Property="Margin" Value="0,10,10,10"/>
        </Style>
        <Style TargetType="TextBlock" x:Key="Label">
            <Setter Property="HorizontalAlignment" Value="Right"/>
            <Setter Property="FontSize" Value="13"/>
            <Setter Property="Foreground" Value="{StaticResource MyBrush}"/>
            <Setter Property="FontFamily" Value="Arial"/>
            <Setter Property="FontWeight" Value="Bold"/>
            <Setter Property="Margin" Value="0,3,10,0"/>
        </Style>
    </Window.Resources>

    <Border>
        <StackPanel>
            <TextBlock Style="{StaticResource TitleText}">Title</TextBlock>
            <TextBlock Style="{StaticResource Label}">Label</TextBlock>
            <TextBlock HorizontalAlignment="Right" FontSize="36" Foreground="{StaticResource MyBrush}" Text="Text" Margin="20" />
            <Button HorizontalAlignment="Left" Height="30" Background="{StaticResource MyBrush}" Margin="40">Button</Button>
            <Ellipse HorizontalAlignment="Center" Width="100" Height="100" Fill="{StaticResource MyBrush}" Margin="10" />
        </StackPanel>
    </Border>

</Window>

Varje element på ramverksnivå (FrameworkElement eller FrameworkContentElement) har en Resources egenskap, som är en ResourceDictionary typ som innehåller definierade resurser. Du kan definiera resurser för alla element, till exempel en Button. Resurser definieras dock oftast på rotelementet, som finns Window i exemplet.

Varje resurs i en resursordlista måste ha en unik nyckel. När du definierar resurser i markering tilldelar du den unika nyckeln via x:Key-direktivet. Vanligtvis är nyckeln en sträng. Du kan dock även ange den till andra objekttyper med hjälp av lämpliga tillägg för markering. Icke-strängnycklar för resurser används av vissa funktionsområden i WPF, särskilt för format, komponentresurser och dataformat.

Du kan använda en definierad resurs med syntaxen för resursmarkeringstillägget som anger resursens nyckelnamn. Använd till exempel resursen som värde för en egenskap i ett annat element.

<Button Background="{StaticResource MyBrush}"/>
<Ellipse Fill="{StaticResource MyBrush}"/>

I föregående exempel, när XAML-inläsaren bearbetar värdet {StaticResource MyBrush} för egenskapen på Background, kontrollerar resurssökningslogik först resursordlistan för elementet ButtonButton. Om Button inte har någon definition av resursnyckeln MyBrush (i det exemplet är den inte det, dess resurssamling är tom) kontrollerar sökningen sedan det överordnade elementet i Button. Om resursen inte har definierats för den överordnade filen fortsätter den att kontrollera objektets logiska träd uppåt tills den hittas.

Om du definierar resurser i rotelementet kan alla element i det logiska trädet, till exempel Window eller Page, komma åt det. Och du kan återanvända samma resurs för att ange värdet för alla egenskaper som accepterar samma typ som resursen representerar. I föregående exempel anger samma MyBrush resurs två olika egenskaper: Button.Background och Ellipse.Fill.

Statiska och dynamiska resurser

En resurs kan refereras till som antingen statisk eller dynamisk. Referenser skapas med hjälp av antingen StaticResource Markup Extension eller DynamicResource Markup Extension. Ett markeringstillägg är en XAML-funktion som gör att du kan ange en objektreferens genom att låta markeringstillägget bearbeta attributsträngen och returnera objektet till en XAML-inläsare. Mer information om beteende för markeringstillägg finns i Markeringstillägg och WPF XAML.

När du använder ett markeringstillägg anger du vanligtvis en eller flera parametrar i strängform som bearbetas av det specifika markeringstillägget. StaticResource Markup Extension bearbetar en nyckel genom att leta upp värdet för den nyckeln i alla tillgängliga resursordlistor. Bearbetningen sker under inläsningen, vilket är när inläsningsprocessen måste tilldela egenskapsvärdet. DynamicResource Markup Extension bearbetar i stället en nyckel genom att skapa ett uttryck, och uttrycket förblir ovärderat tills appen körs, då uttrycket utvärderas för att ange ett värde.

När du refererar till en resurs kan följande överväganden påverka om du använder en referens för statiska resurser eller en dynamisk resursreferens:

  • När du fastställer den övergripande designen för hur du skapar resurser för din app (per sida, i appen, i lös XAML eller i en resurssammansättning) bör du tänka på följande:

  • Appens funktioner. Ingår uppdatering av resurser i realtid i dina appkrav?

  • Respektive uppslagsbeteende för den resursreferenstypen.

  • Den specifika egenskapen eller resurstypen och det interna beteendet för dessa typer.

Statiska resurser

Statiska resursreferenser fungerar bäst under följande omständigheter:

  • Appdesignen koncentrerar de flesta av sina resurser till resursordlistor på sid- eller programnivå.

    Statiska resursreferenser omvärderas inte baserat på körningsbeteenden, till exempel att läsa in en sida igen. Det kan därför finnas vissa prestandafördelar för att undvika ett stort antal dynamiska resursreferenser när de inte behövs baserat på din resurs- och appdesign.

  • Du anger värdet för en egenskap som inte finns på en DependencyObject eller en Freezable.

  • Du skapar en resursordlista som kompileras till en DLL som delas mellan appar.

  • Du skapar ett tema för en anpassad kontroll och definierar resurser som används inom temana.

    I det här fallet vill du vanligtvis inte ha uppslagsbeteendet för dynamisk resursreferens. Använd i stället referensbeteendet för statiska resurser så att sökningen är förutsägbar och fristående i temat. Med en dynamisk resursreferens lämnas även en referens inom ett tema outvärderad förrän vid körning. Och det finns en chans att när temat tillämpas omdefinierar något lokalt element en nyckel som ditt tema försöker referera till, och det lokala elementet hamnar före själva temat i uppslaget. Om det händer kommer temat inte att fungera som förväntat.

  • Du använder resurser för att ange ett stort antal beroendeegenskaper. Beroendeegenskaper har effektiv värdecachelagring som aktiveras av egenskapssystemet, så om du anger ett värde för en beroendeegenskap som kan utvärderas vid belastningen behöver beroendeegenskapen inte söka efter ett omvärderat uttryck och returnera det senaste effektiva värdet. Den här tekniken kan vara en prestandafördel.

  • Du vill ändra den underliggande resursen för alla konsumenter, eller så vill du underhålla separata skrivbara instanser för varje konsument med hjälp av x:Shared Attribute.

Beteende för statisk resurssökning

Följande beskriver uppslagsprocessen som sker automatiskt när en statisk resurs refereras till av en egenskap eller ett element:

  1. Sökningsprocessen söker efter den begärda nyckeln i resursordlistan som definierats av elementet som anger egenskapen.

  2. Uppslagsprocessen passerar sedan det logiska trädet uppåt till det överordnade elementet och dess resursordlista. Den här processen fortsätter tills rotelementet har nåtts.

  3. Appresurser kontrolleras. Appresurser är de resurser i resursordlistan som definieras av Application objektet för DIN WPF-app.

Statiska resursreferenser från en resursordlista måste referera till en resurs som redan har definierats lexikalt före resursreferensen. Det går inte att lösa en framåtreferens med en statisk resursreferens. Därför utformar du resursordlistestrukturen så att resurserna definieras i eller i början av varje resursordlista.

Statisk resurssökning kan utökas till teman eller till systemresurser, men den här sökningen stöds bara eftersom XAML-inläsaren defersar begäran. Fördröjningen är nödvändig så att temat vid körningstid när sidan laddas tillämpas korrekt i appen. Men statiska resursreferenser till nycklar som är kända för att bara finnas i teman eller som systemresurser rekommenderas inte, eftersom sådana referenser inte omvärderas om temat ändras av användaren i realtid. En dynamisk resursreferens är mer tillförlitlig när du begär tema- eller systemresurser. Undantaget är när ett temaelement självt begär en annan resurs. Dessa referenser bör vara statiska resursreferenser av de skäl som nämnts tidigare.

Undantagsbeteendet om en statisk resursreferens inte hittas varierar. Om resursen har skjutits upp inträffar undantaget under körning. Om resursen inte har skjutits upp sker undantaget vid belastningstillfället.

Dynamiska resurser

Dynamiska resurser fungerar bäst när:

  • Värdet för resursen, inklusive systemresurser eller resurser som annars kan ställas in av användaren, beror på villkor som inte är kända förrän körningen. Du kan till exempel skapa setter-värden som refererar till systemegenskaper som exponerade av SystemColors, SystemFontseller SystemParameters. Dessa värden är verkligen dynamiska eftersom de i slutändan kommer från körningsmiljön för användaren och operativsystemet. Du kan också ha teman på programnivå som kan ändras, där resursåtkomst på sidnivå också måste samla in ändringen.

  • Du skapar eller refererar till temaformat för en anpassad kontroll.

  • Du tänker justera innehållet i en ResourceDictionary under en appens livstid.

  • Du har en komplicerad resursstruktur som har beroenden, där en referens framåt kan krävas. Statiska resursreferenser har inte stöd för vidarekopplingsreferenser, men dynamiska resursreferenser stöder dem eftersom resursen inte behöver utvärderas förrän körningen, och vidarekopplingsreferenser är därför inte ett relevant begrepp.

  • Du refererar till en resurs som är stor ur kompilerings- eller arbetsuppsättningens perspektiv, och resursen kanske inte används direkt när sidan läses in. Statiska resursreferenser läses alltid in från XAML när sidan läses in. En dynamisk resursreferens läses dock inte in förrän den används.

  • Du skapar ett format där settervärden kan komma från andra värden som påverkas av teman eller andra användarinställningar.

  • Du tillämpar resurser på element som kan omformas eller flyttas i det logiska trädet under appens livstid. Om du ändrar överordnad kan även resurssökningsomfånget ändras, så om du vill att resursen för ett omvärderat element ska omvärderas baserat på det nya omfånget använder du alltid en dynamisk resursreferens.

Dynamiskt resurssökningsbeteende

Resurssökningsbeteendet för en dynamisk resursreferens liknar sökningsbeteendet i din kod om du anropar FindResource eller SetResourceReference.

  1. Sökningen söker efter den begärda nyckeln i resursordlistan som definierats av elementet som anger egenskapen:

  2. Sökningen passerar det logiska trädet uppåt till det överordnade elementet och dess resursordlista. Den här processen fortsätter tills rotelementet har nåtts.

  3. Appresurser kontrolleras. Appresurser är de resurser i resursordlistan som definieras av Application objektet för DIN WPF-app.

  4. Temaresursordlistan kontrolleras för det aktuella temat. Om temat ändras under körning omvärderas värdet.

  5. Systemresurser kontrolleras.

Undantagsbeteendet (om det finns något) varierar:

  • Om en resurs begärdes av ett FindResource anrop och inte hittades utlöses ett undantag.

  • Om en resurs begärdes av ett TryFindResource anrop och inte hittades genereras inget undantag och det returnerade värdet är null. Om egenskapen som anges inte accepterar nullär det fortfarande möjligt att ett djupare undantag utlöses, beroende på vilken enskild egenskap som anges.

  • Om en resurs begärdes av en dynamisk resursreferens i XAML och inte hittades beror beteendet på det allmänna egenskapssystemet. Det allmänna beteendet är som om ingen egenskapsinställningsåtgärd inträffade på den nivå där resursen finns. Om du till exempel försöker ange bakgrunden för ett enskilt knappelement med hjälp av en resurs som inte kunde utvärderas, sätts inget värde, men det effektiva värdet kan fortfarande komma från andra deltagare i egenskapssystemet och värdeprioritet. Till exempel kan bakgrundsvärdet fortfarande komma från ett lokalt definierat knappformat eller från temaformatet. För egenskaper som inte definieras av temaformat kan det effektiva värdet efter en misslyckad resursutvärdering komma från standardvärdet i egenskapsmetadata.

Begränsningar

Dynamiska resursreferenser har några viktiga begränsningar. Minst ett av följande villkor måste vara sant:

Eftersom egenskapen som anges måste vara en DependencyProperty eller Freezable -egenskap kan de flesta egenskapsändringar spridas till användargränssnittet eftersom en egenskapsändring (det ändrade dynamiska resursvärdet) bekräftas av egenskapssystemet. De flesta kontroller innehåller logik som tvingar fram en annan layout för en kontroll om DependencyProperty förändras och denna egenskap kan påverka layouten. Men inte alla egenskaper som har ett DynamicResource Markup-tillägg som deras värde garanteras att tillhandahålla realtidsuppdateringar i användargränssnittet. Den funktionen kan fortfarande variera beroende på egenskapen och beroende på vilken typ som äger egenskapen, eller till och med appens logiska struktur.

Stilar, DataTemplates och implicita nycklar

Även om alla objekt i en ResourceDictionary måste ha en nyckel betyder det inte att alla resurser måste ha en explicit x:Key. Flera objekttyper stöder en implicit nyckel när den definieras som en resurs, där nyckelvärdet är kopplat till värdet för en annan egenskap. Den här typen av nyckel kallas implicit nyckel och ett x:Key attribut är en explicit nyckel. Du kan skriva över en implicit nyckel genom att ange en explicit nyckel.

Ett viktigt scenario för resurser är när du definierar en Style. I själva verket definieras en Style nästan alltid som en post i en resursordlista, eftersom formatmallar är avsedda för återanvändning. Mer information om format finns i Format och mallar (WPF .NET).

Format för kontroller kan både skapas med och refereras till med en implicit nyckel. De temaformat som definierar standardutseendet för en kontroll förlitar sig på den här implicita nyckeln. När det gäller att begära det är Type den implicita nyckeln själva kontrollens. När det gäller att definiera resurserna är TargetType den implicita nyckeln till stilen. Om du skapar teman för anpassade kontroller eller skapar format som interagerar med befintliga temaformat behöver du därför inte ange ett x:Key-direktiv för det Style. Och om du vill använda temaformaten behöver du inte ange något format alls. Följande formatdefinition fungerar till exempel, även om resursen Style inte verkar ha någon nyckel:

<Style TargetType="Button">
    <Setter Property="Background" Value="#4E1A3D" />
    <Setter Property="Foreground" Value="White" />
    <Setter Property="BorderThickness" Value="5" />
    <Setter Property="BorderBrush">
        <Setter.Value>
            <LinearGradientBrush>
                <GradientStop Offset="0.0" Color="#4E1A3D"/>
                <GradientStop Offset="1.0" Color="Salmon"/>
            </LinearGradientBrush>
        </Setter.Value>
    </Setter>
</Style>

Det formatet har verkligen en nyckel: den implicita nyckeln: typen System.Windows.Controls.Button . I markering kan du ange ett TargetType direkt som typnamn (eller så kan du använda {x:Type...} för att returnera en Type.

Genom de standardtemaformatmekanismer som används av WPF appliceras den stilen som körningstidsstil för en Button på sidan, även om Button inte försöker ange dess Style-egenskap eller en specifik resursreferens till stilen. Formatmallen som definierats på sidan finns tidigare i uppslagssekvensen än temaordlisteformatet med samma nyckel som temaordlisteformatet har. Du kan bara ange <Button>Hello</Button> var som helst på sidan, och formatet som du definierade med TargetTypeButton skulle gälla för den knappen. Om du vill kan du fortfarande uttryckligen ange formatet med samma typvärde som TargetType för tydlighetens skull, men det är valfritt.

Implicita nycklar för formatmallar gäller inte för en kontroll om OverridesDefaultStyle är true. (Observera också att OverridesDefaultStyle kan anges som en del av det interna beteendet för kontrollklassen, snarare än uttryckligen på en instans av kontrollen.) För att stödja implicita nycklar för härledda klassscenarier måste kontrollen också åsidosättas DefaultStyleKey (alla befintliga kontroller som tillhandahålls som en del av WPF inkluderar den här åsidosättningen). Mer information om format, teman och kontrolldesign finns i Riktlinjer för design av stilabla kontroller.

DataTemplate har också en implicit nyckel. Den implicita nyckeln för en DataTemplate är egenskapsvärdet DataType . DataType kan också anges som namnet på typen i stället för att uttryckligen använda {x:Type...}. Mer information finns i Översikt över dataöverläggning.

Se även