Dela via


Översikt över beroendeegenskaper

I det här avsnittet beskrivs det beroendeegenskapssystem som är tillgängligt när du skriver en Windows Runtime-app med XAML-definitioner för användargränssnittet.

Vad är en beroendeegenskap?

En beroendeegenskap är en specialiserad typ av egenskap. Specifikt är det en egenskap där egenskapens värde spåras och påverkas av ett dedikerat egenskapssystem som ingår i Windows Runtime.

För att stödja en beroendeegenskap måste objektet som definierar egenskapen vara en DependencyObject (med andra ord en klass som har base-klassen DependencyObject någonstans i arv). Många av de typer som du använder för dina användargränssnittsdefinitioner för en UWP-app med XAML är underklassen DependencyObject och stöder beroendeegenskaper. Men alla typer som kommer från ett Windows Runtime-namnområde som inte har "XAML" i namnet stöder inte beroendeegenskaper. egenskaper för sådana typer är vanliga egenskaper som inte har egenskapssystemets beroendebeteende.

Syftet med beroendeegenskaper är att tillhandahålla ett systemiskt sätt att beräkna värdet för en egenskap baserat på andra indata (andra egenskaper, händelser och tillstånd som inträffar i din app medan den körs). Dessa andra indata kan vara:

  • Externa indata, till exempel användarinställningar
  • Mekanismer för just-in-time-egenskapsbestämning, till exempel databindning, animeringar och storyboards
  • Mallmönster med flera användningsområden, till exempel resurser och formatmallar
  • Värden som är kända via överordnade och underordnade relationer med andra element i objektträdet

En beroendeegenskap representerar eller stöder en specifik funktion i programmeringsmodellen för att definiera en Windows Runtime-app med XAML för användargränssnittet. Dessa funktioner omfattar bland annat:

  • Datalänkning
  • Stilar
  • Storyboarded-animeringar
  • "PropertyChanged"-beteende; en beroendeegenskap kan implementeras för att tillhandahålla återanrop som kan sprida ändringar till andra beroendeegenskaper
  • Använda ett standardvärde som kommer från egenskapsmetadata
  • Generellt egenskapssystemverktyg som ClearValue och metadatasökning

Beroendeegenskaper och Windows Runtime-egenskaper

Beroendeegenskaper utökar grundläggande Windows Runtime-egenskapsfunktioner genom att tillhandahålla ett globalt, internt egenskapslager som säkerhetskopierar alla beroendeegenskaper i en app vid körning. Det här är ett alternativ till standardmönstret för att stöda en egenskap med ett privat fält som är privat inom egenskapsdefinitionsklassen. Du kan se det här interna egenskapsarkivet som en uppsättning egenskapsidentifierare och värden som finns för ett visst objekt (så länge det är ett DependencyObject). I stället för att identifieras med namn, identifieras varje egenskap i lagret av en DependencyProperty-instans. Men egenskapssystemet döljer mestadels den här implementeringsinformationen: du kan vanligtvis komma åt beroendeegenskaper med hjälp av ett enkelt namn (det programmatiska egenskapsnamnet på det kodspråk du använder eller ett attributnamn när du skriver XAML).

Bastypen som tillhandahåller grunderna för beroendeegenskapssystemet är DependencyObject. DependencyObject definierar metoder som kan komma åt beroendeegenskapen, och instanser av en DependencyObject-härledd klass stöder internt det egenskapsarkivkoncept som vi nämnde tidigare.

Här är en sammanfattning av den terminologi som vi använder i dokumentationen när vi diskuterar beroendeegenskaper:

Begrepp Description
Beroendeegenskap En egenskap som finns på en DependencyProperty-identifierare (se nedan). Vanligtvis är den här identifieraren tillgänglig som en statisk medlem i den definierande DependencyObject-härledda klassen.
Identifierare för beroendeegenskap Ett konstant värde för att identifiera egenskapen, det är vanligtvis publikt och skrivskyddat.
Egenskapsomslutning Anropbara metoder get och set för en Windows Runtime-egenskap. Eller den språkspecifika projektionen av den ursprungliga definitionen. Implementeringen get property wrapper anropar GetValue och skickar relevant beroendeegenskapsidentifierare.

Egenskapsomslutningen är inte bara bekvämlighet för anropare, den exponerar även beroendeegenskapen för alla processer, verktyg eller projektioner som använder Windows Runtime-definitioner för egenskaper.

I följande exempel definieras en anpassad beroendeegenskap enligt definitionen för C# och relationen mellan beroendeegenskapsidentifieraren och egenskapsomslutningen.

public static readonly DependencyProperty LabelProperty = DependencyProperty.Register(
  "Label",
  typeof(string),
  typeof(ImageWithLabelControl),
  new PropertyMetadata(null)
);


public string Label
{
    get { return (string)GetValue(LabelProperty); }
    set { SetValue(LabelProperty, value); }
}

Anmärkning

Föregående exempel är inte avsett som det fullständiga exemplet för hur du skapar en anpassad beroendeegenskap. Den är avsedd att visa begrepp för beroendeegenskap för alla som föredrar inlärningsbegrepp via kod. En mer fullständig förklaring av det här exemplet finns i Anpassade beroendeegenskaper.

Prioritet för beroendeegenskapsvärde

När du får värdet för en beroendeegenskap får du ett värde som fastställdes för den egenskapen via någon av de indata som deltar i Windows Runtime-egenskapssystemet. Prioritet för beroendeegenskapsvärden finns så att Windows Runtime-egenskapssystemet kan beräkna värden på ett förutsägbart sätt, och det är viktigt att du är bekant med den grundläggande prioritetsordningen också. Annars kan du hamna i en situation där du försöker ange en egenskap på en prioritetsnivå, men något annat (systemet, anropare från tredje part, en del av din egen kod) ställer in den på en annan nivå och du blir frustrerad när du försöker ta reda på vilket egenskapsvärde som används och var värdet kommer ifrån.

Till exempel är stilmallar och mallar avsedda att vara en gemensam startpunkt för att upprätta egenskapsvärden och därmed utseendet på en kontroll. Men på en viss kontrollinstans kanske du vill ändra dess värde jämfört med det vanliga mallade värdet, till exempel att ge den kontrollen en annan bakgrundsfärg eller en annan textsträng som innehåll. Windows Runtime-egenskapssystemet tar hänsyn till lokala värden med högre prioritet än värden som tillhandahålls av format och mallar. Det möjliggör scenariot där appspecifika värden skrivs över mallarna så att kontrollerna blir användbara för din egen användning i appens användargränssnitt.

Prioritetsordning för beroendeegenskaper

Följande är den definitiva ordningen som egenskapssystemets använder när man tilldelar ett körningsvärde för en beroendeegenskap. Högsta prioritet visas först. Du hittar mer detaljerade förklaringar precis efter den här listan.

  1. Animerade värden: Aktiva animeringar, animeringar av visuellt tillstånd eller animeringar med ett HoldEnd-beteende . För att få någon praktisk effekt måste en animering som tillämpas på en egenskap ha företräde framför basvärdet (oanimerat), även om det värdet har angetts lokalt.
  2. Lokalt värde: Ett lokalt värde kan anges genom bekvämligheten med egenskapsomslutningen, vilket också motsvarar inställningen som ett attribut eller egenskapselement i XAML, eller genom ett anrop till Metoden SetValue med hjälp av en egenskap för en specifik instans. Om du anger ett lokalt värde med hjälp av en bindning eller en statisk resurs agerar dessa i prioriteten som om ett lokalt värde angavs och bindningar eller resursreferenser raderas om ett nytt lokalt värde anges.
  3. Mallade egenskaper: Ett element har dessa om det skapades som en del av en mall (från en ControlTemplate eller DataTemplate).
  4. Stilsättare: Värden från en Setter i stilar från sid- eller programresurser.
  5. Standardvärde: En beroendeegenskap kan ha ett standardvärde som en del av dess metadata.

Mallade egenskaper

Mallade egenskaper som ett prioritetsobjekt gäller inte för någon egenskap för ett element som du deklarerar direkt i XAML-sidmarkeringen. Det mallade egenskapskonceptet finns bara för objekt som skapas när Windows Runtime tillämpar en XAML-mall på ett användargränssnittselement och därmed definierar dess visuella objekt.

Alla egenskaper som anges från en kontrollmall har värden av något slag. Dessa värden är nästan som en utökad uppsättning standardvärden för kontrollen och associeras ofta med värden som du kan återställa senare genom att ange egenskapsvärdena direkt. Därför måste malluppsättningsvärdena skiljas från ett verkligt lokalt värde, så att alla nya lokala värden kan skriva över det.

Anmärkning

I vissa fall kan mallen åsidosätta även lokala värden, om mallen inte kunde exponera {TemplateBinding}-referenser för egenskaper som skulle ha kunnat ställas in på instanser. Detta görs vanligtvis bara om egenskapen verkligen inte är avsedd att anges för instanser, till exempel om den bara är relevant för visuella objekt och mallbeteende och inte för den avsedda funktionen eller körningslogik för kontrollen som använder mallen.

Bindningar och prioritet

Bindningsåtgärder har rätt prioritet för det omfång de används för. En {Binding} som tillämpas på ett lokalt värde fungerar till exempel som ett lokalt värde, och ett {TemplateBinding}-markeringstillägg för en egenskapsinställning gäller som en stilinställning gör. Eftersom bindningar måste vänta till körning för att hämta värden från datakällor, utökas även processen för att fastställa egenskapens värdeöverhöghet för en egenskap till körning.

Bindningar opererar inte bara med samma prioritet som ett lokalt värde, de är verkligen ett lokalt värde, där bindningen är platshållaren för ett värde som fördröjs. Om du har en bindning på plats för ett egenskapsvärde och du anger ett lokalt värde på den vid körningstid, ersätter det bindningen helt. Om du anropar SetBinding för att definiera en bindning som bara finns vid körning ersätter du alla lokala värden som du kan ha tillämpat i XAML eller med tidigare körd kod.

Storyboarded-animeringar och basvärde

Storyboarded-animeringar fungerar på ett koncept med ett basvärde. Basvärdet är det värde som bestäms av egenskapssystemet med dess prioritet, men utelämnar det sista steget för att söka efter animeringar. Ett basvärde kan till exempel komma från en kontrolls mall, eller så kan det komma från att ange ett lokalt värde på en instans av en kontroll. Hur som helst, om du använder en animering skrivs det här basvärdet över och det animerade värdet tillämpas så länge animeringen fortsätter att köras.

För en animerad egenskap kan basvärdet fortfarande påverka animeringens beteende, om animeringen inte uttryckligen anger både Från och Till, eller om animeringen återställer egenskapen till dess basvärde när den är klar. I dessa fall används resten av prioriteten igen när en animering inte längre körs.

En animering som anger en To med ett HoldEnd-beteende kan dock åsidosätta ett lokalt värde tills animeringen tas bort, även när den visuellt verkar vara stoppad. Konceptuellt är detta som en animering som körs för alltid även om det inte finns någon visuell animering i användargränssnittet.

Flera animeringar kan tillämpas på en enda egenskap. Var och en av dessa animeringar kan ha definierats för att ersätta basvärden som kom från olika punkter i värdeprioriteten. De här animeringarna körs dock samtidigt vid körning, och det innebär ofta att de måste kombinera sina värden eftersom varje animering har samma inverkan på värdet. Detta beror på exakt hur animeringarna definieras och vilken typ av värde som animeras.

Mer information finns i Storyboarded-animeringar.

Standardvärden

Om du upprättar standardvärdet för en beroendeegenskap med ett PropertyMetadata-värde förklaras mer detaljerat i avsnittet Anpassade beroendeegenskaper .

Beroendeegenskaper har fortfarande standardvärden även om standardvärdena inte uttryckligen har definierats i den egenskapens metadata. Om de inte har ändrats med metadata är standardvärdena för beroendeegenskaperna för Windows Runtime vanligtvis något av följande:

  • En egenskap som använder ett körningsobjekt eller den grundläggande objekttypen (en referenstyp) har standardvärdet null. DataContext är till exempel null tills det avsiktligt har angetts eller ärvts.
  • En egenskap som använder ett grundläggande värde, till exempel tal eller ett booleskt värde (en värdetyp) använder en förväntad standard för det värdet. Till exempel 0 för heltal och flyttalsnummer, falskt för ett booleskt värde.
  • En egenskap som använder en Windows Runtime-struktur har ett standardvärde som erhålls genom att anropa den strukturens implicita standardkonstruktor. Den här konstruktorn använder standardvärdena för vart och ett av de grundläggande värdefälten i strukturen. Ett standardvärde för ett punktvärde initieras till exempel med dess X - och Y-värden som 0.
  • En egenskap som använder en uppräkning har ett standardvärde för den första definierade medlemmen i uppräkningen. Kontrollera referensen för specifika uppräkningar för att se vad standardvärdet är.
  • En egenskap som använder en sträng (System.String för .NET, Platform::String for C++/CX) har ett standardvärde för en tom sträng ("").
  • Samlingsegenskaper implementeras vanligtvis inte som beroendeegenskaper, av skäl som beskrivs ytterligare i det här avsnittet. Men om du implementerar en anpassad samlingsegenskap och vill att den ska vara en beroendeegenskap bör du undvika en oavsiktlig singleton enligt beskrivningen nära slutet av Anpassade beroendeegenskaper.

Egenskapsfunktioner som tillhandahålls av en beroendeegenskap

Datalänkning

En beroendeegenskap kan ha värdet inställt genom att tillämpa en databindning. Databindningen använder syntaxen för {Binding}-markeringstillägget i XAML, {x:Bind} markeringstillägg eller bindningsklassen i kod. För en databunden egenskap skjuts den slutliga egenskapsvärdebestämningen upp till körningstiden. Då hämtas värdet från en datakälla. Den roll som systemet för beroendeegenskaper spelar här är att möjliggöra en platshållarfunktionalitet för operationer som att läsa in XAML när värdet ännu inte är känt, och sedan ange värdet vid körning genom interaktion med databindningsmotorn i Windows Runtime.

I följande exempel anges textvärdet för ett TextBlock-element med hjälp av en bindning i XAML. Bindningen använder en ärvd datakontext och en objektdatakälla. (Inget av dessa visas i det förkortade exemplet. Ett mer komplett exempel som visar kontext och källa finns i Databindning på djupet.)

<Canvas>
  <TextBlock Text="{Binding Team.TeamName}"/>
</Canvas>

Du kan också upprätta bindningar med hjälp av kod i stället för XAML. Mer information om SetBinding.

Anmärkning

Bindningar som denna betraktas som ett lokalt värde i samband med prioritet av beroendeegenskapers värde. Om du anger ett annat lokalt värde för en egenskap som ursprungligen hade ett bindningsvärde skriver du över bindningen helt och hållet, inte bara bindningens körningsvärde. {x:Bind} Bindningar implementeras med genererad kod som anger ett lokalt värde för egenskapen. Om du anger ett lokalt värde för en egenskap som använder {x:Bind}, ersätts det värdet nästa gång bindningen utvärderas, till exempel när den observerar en egenskapsändring för källobjektet.

Bindningskällor, bindningsmål, rollen för FrameworkElement

För att vara källan till en bindning behöver en egenskap inte vara en beroendeegenskap. Du kan vanligtvis använda alla egenskaper som en bindningskälla, även om detta beror på ditt programmeringsspråk och var och en har vissa gränsfall. Men för att vara målet för ett {Binding}-markeringstillägg eller bindning måste den egenskapen vara en beroendeegenskap. {x:Bind} har inte det här kravet eftersom den använder genererad kod för att tillämpa sina bindningsvärden.

Om du skapar en bindning i kod bör du observera att SetBinding-API :et endast har definierats för FrameworkElement. Du kan dock skapa en bindningsdefinition med Hjälp av BindingOperations i stället och därmed referera till valfri DependencyObject-egenskap .

Kom ihåg att DataContext är en FrameworkElement-egenskap för antingen kod eller XAML. Genom att använda en form av överordnad-underordnad egenskapsarv (som vanligtvis upprättas i XAML-markering) kan bindningssystemet fastställa en DataContext som finns på ett överordnat element. Det här arvet kan utvärderas även om det underordnade objektet (som har målegenskapen) inte är ett FrameworkElement och därmed inte behåller ett eget DataContext-värde. Det överordnade elementet som ärvs måste dock vara ett FrameworkElement för att kunna ange och lagra DataContext. Du måste också definiera bindningen så att den kan fungera med ett null-värde för DataContext.

Att koppla bindningen är inte det enda som behövs för de flesta databindningsscenarier. För att en envägs- eller tvåvägsbindning ska vara effektiv måste källegenskapen ha stöd för ändringsmeddelanden som sprids till bindningssystemet och därmed målet. För anpassade bindningskällor innebär det att egenskapen måste vara en beroendeegenskap, annars måste objektet ha stöd för INotifyPropertyChanged. Samlingar bör ha stöd för INotifyCollectionChanged. Vissa klasser stöder dessa gränssnitt i implementeringarna så att de är användbara som basklasser för databindningsscenarier. ett exempel på en sådan klass är ObservableCollection<T>. Mer information om databindning och hur databindning relaterar till egenskapssystemet finns i Databindning på djupet.

Anmärkning

De typer som anges här stöder Microsoft .NET-datakällor. C++/CX-datakällor använder olika gränssnitt för ändringsmeddelanden eller observerbart beteende, se Databindning på djupet.

Formatmallar och stilar

Mallar och stilmallar är två av de scenarier där egenskaper definieras som beroendeegenskaper. Format är användbara för att ange egenskaper som definierar appens användargränssnitt. Formatmallar definieras som resurser i XAML, antingen som en post i en resurssamling eller i separata XAML-filer, till exempel temaresursordlistor. Stilar interagerar med egenskapssystemet eftersom de innehåller setters för egenskaper. Den viktigaste egenskapen här är egenskapen Control.Template för en kontroll: den definierar det mesta av det visuella utseendet och det visuella tillståndet för en kontroll. Mer information om formatmallar och några exempel på XAML som definierar ett format och använder setters finns i Formateringskontroller.

Värden som kommer från formatmallar eller mallar är uppskjutna värden, ungefär som bindningar. Detta gör att kontrollanvändare kan ommalla kontroller eller omdefiniera formatmallar. Därför kan egenskapssättare i format bara påverka beroendeegenskaper, inte vanliga egenskaper.

Storyboarded-animeringar

Du kan animera värdet för en beroendeegenskap med hjälp av en storyboardad animering. Storyboarded animationer i Windows Runtime är inte bara visuella dekorationer. Det är mer användbart att tänka på animeringar som en tillståndsdatorteknik som kan ange värdena för enskilda egenskaper eller för alla egenskaper och visuella objekt för en kontroll och ändra dessa värden över tid.

För att kunna animeras måste animeringens målegenskap vara en beroendeegenskap. För att vara animerad måste målegenskapens värdetyp också stödjas av någon av de befintliga animeringstyperna som härleds från Timeline. Värden för färg, dubbel och punkt kan animeras med hjälp av antingen interpolerings- eller nyckelbildstekniker. De flesta andra värden kan animeeras med diskreta objektnyckelramar .

När en animering tillämpas och körs fungerar det animerade värdet med högre prioritet än något värde (till exempel ett lokalt värde) som egenskapen annars har. Animeringar har också ett valfritt HoldEnd-beteende som kan orsaka att animeringar tillämpas på egenskapsvärden även om animeringen visuellt verkar stoppas.

Principen för tillståndsdatorn förkroppsligas av användningen av storyboardade animeringar som en del av VisualStateManager-tillståndsmodellen för kontroller. Mer information om storyboardade animeringar finns i Storyboarded-animeringar. Mer information om VisualStateManager och hur du definierar visuella tillstånd för kontroller finns i Storyboarded-animeringar för visuella tillstånd eller kontrollmallar.

Beteende vid egenskapsförändring

Egenskapsförändringsbeteende är ursprunget till den "beroende" delen av beroendeegenskapsterminologin. Att upprätthålla giltiga värden för en egenskap när en annan egenskap kan påverka den första egenskapens värde är ett svårt utvecklingsproblem i många ramverk. I Windows Runtime-egenskapssystemet kan varje beroendeegenskap ange ett återanrop som anropas när dess egenskapsvärde ändras. Det här återanropet kan användas för att meddela eller ändra relaterade egenskapsvärden, vanligtvis på ett synkront sätt. Många befintliga beroendeegenskaper har ett egenskapsbaserat beteende. Du kan också lägga till liknande återanropshantering till anpassade beroendeegenskaper och implementera dina egna egenskapsändrade återanrop. Ett exempel finns i Anpassade beroendeegenskaper .

Windows 10 introducerar metoden RegisterPropertyChangedCallback . På så sätt kan programkoden registrera sig för ändringsmeddelanden när den angivna beroendeegenskapen ändras på en instans av DependencyObject.

Standardvärde och ClearValue

En beroendeegenskap kan ha ett standardvärde som definierats som en del av dess egenskapsmetadata. För en beroendeegenskap blir standardvärdet inte irrelevant när egenskapen har angetts första gången. Standardvärdet kan tillämpas igen under körning när någon annan determinant i värdeprioritet försvinner. (Prioritet för beroendeegenskapsvärden beskrivs i nästa avsnitt.) Du kan till exempel avsiktligt ta bort ett formatvärde eller en animering som gäller för en egenskap, men du vill att värdet ska vara en rimlig standard när du gör det. Standardvärdet för beroendeegenskapen kan ange det här värdet, utan att specifikt behöva ange varje egenskaps värde som ett extra steg.

Du kan avsiktligt ange en egenskap till standardvärdet även efter att du redan har angett den med ett lokalt värde. Om du vill återställa ett värde som ska vara standard igen, och även för att aktivera andra deltagare i prioritet som kan åsidosätta standardvärdet men inte ett lokalt värde, anropar du Metoden ClearValue (refererar till egenskapen för att rensa som en metodparameter). Du vill inte alltid att egenskapen bokstavligen ska använda standardvärdet, men om du rensar det lokala värdet och återgår till standardvärdet kan du aktivera ett annat objekt i prioritet som du vill agera nu, till exempel att använda värdet som kom från en formatuppsättning i en kontrollmall.

DependencyObject och trådhantering

Alla DependencyObject-instanser måste skapas i användargränssnittstråden som är associerad med det aktuella fönstret som visas av en Windows Runtime-app. Även om varje DependencyObject måste skapas i huvudgränssnittstråden kan objekten nås med hjälp av en dispatcher-referens från andra trådar genom att komma åt egenskapen DispatcherQueue . Sedan kan du anropa metoder som TryEnqueue och köra koden inom reglerna för trådbegränsningar i användargränssnittstråden.

Anmärkning

För UWP-appar får du åtkomst till egenskapen Dispatcher . Sedan kan du anropa metoder som RunAsyncCoreDispatcher-objektet och köra koden inom reglerna för trådbegränsningar i användargränssnittstråden. Mer information om skillnaderna mellan UWP och WinUI för Windows App SDK finns i Trådfunktionsmigrering.

Trådaspekterna i DependencyObject är relevanta eftersom det i allmänhet innebär att endast kod som körs i användargränssnittstråden kan ändra eller till och med läsa värdet för en beroendeegenskap. Trådproblem kan vanligtvis undvikas i typisk användargränssnittskod som använder asynkrona mönster och bakgrundstrådar i arbetsytan. Du stöter vanligtvis bara på DependencyObject-relaterade trådproblem om du definierar dina egna DependencyObject-typer och försöker använda dem för datakällor eller andra scenarier där ett DependencyObject inte nödvändigtvis är lämpligt.

Konceptuellt material