Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Genom att förstå wpf-objektens inbyggda beteende kan du göra rätt kompromisser mellan funktioner och prestanda.
Att inte ta bort händelsehanterare från objekt kan göra att objekten förblir aktiva.
Ombudet som ett objekt skickar till sin händelse är i praktiken en referens till objektet. Därför kan händelsehanterare hålla objekt vid liv längre än förväntat. När du rensar ett objekt som har registrerats för att lyssna på ett objekts händelse är det viktigt att ta bort det delegat som lyssnar på det objektets händelse innan objektet släpps. Att hålla onödiga objekt vid liv ökar programmets minnesanvändning. Detta gäller särskilt när objektet är roten till ett logiskt träd eller ett visuellt träd.
WPF introducerar ett svagt händelselyssnaremönster för händelser som kan vara användbara i situationer där objektets livslängdsrelationer mellan källa och lyssnare är svåra att hålla reda på. Vissa befintliga WPF-händelser använder det här mönstret. Om du implementerar objekt med anpassade händelser kan det här mönstret vara till nytta för dig. Mer information finns i svaga händelsemönster.
Det finns flera verktyg, till exempel CLR Profiler och visningsprogrammet för arbetsuppsättningar, som kan ge information om minnesanvändningen för en angiven process. CLR Profiler innehåller ett antal mycket användbara vyer av allokeringsprofilen, inklusive ett histogram över allokerade typer, allokerings- och anropsdiagram, en tidsrad som visar skräpsamlingar av olika generationer och det resulterande tillståndet för den hanterade heapen efter dessa samlingar och ett anropsträd som visar allokeringar per metod och sammansättningsbelastningar. Mer information finns i Prestanda.
Beroendeegenskaper och -objekt
I allmänhet går det inte långsammare att komma åt en beroendeegenskap för en DependencyObject än att komma åt en CLR-egenskap. Även om det finns en liten prestandakostnad för att ange ett egenskapsvärde är det lika snabbt att få ett värde som att hämta värdet från en CLR-egenskap. Att kompensera för de små prestandakostnaderna är det faktum att beroendeegenskaper stöder robusta funktioner, till exempel databindning, animering, arv och formatering. Mer information hittar du i översikt över beroendeegenskaper.
DependencyProperty optimeringar
Du bör definiera beroendeegenskaper i ditt program mycket noggrant. Om din DependencyProperty endast påverkar metadataalternativ för renderingstyp, i stället för andra metadataalternativ som AffectsMeasure, bör du markera det som sådant genom att åsidosätta dess metadata. Mer information om hur du åsidosätter eller hämtar egenskapsmetadata finns i Metadata för beroendeegenskaper.
Det kan vara mer effektivt att låta en egenskapsändringshanterare manuellt ogiltigförklara mått-, ordnings- och renderingsomgångar om inte alla egenskapsändringar faktiskt påverkar dessa omgångar. Du kan till exempel välja att åter återge en bakgrund endast när ett värde är större än en angivet gräns. I det här fallet skulle egenskapsändringshanteraren bara ogiltigförklara återgivningen när värdet överskrider den angivna gränsen.
Att göra en DependencyProperty ärverbar är inte kostnadsfri
Som standard är registrerade beroendeegenskaper inte ärverbara. Du kan dock uttryckligen göra alla egenskaper ärvbara. Även om detta är en användbar funktion, påverkar att göra en egenskap ärvbar prestandan genom att öka tiden för egenskapsinvalidering.
Använd RegisterClassHandler noggrant
När du anropar RegisterClassHandler kan du spara instanstillståndet, men det är viktigt att vara medveten om att hanteraren anropas på varje instans, vilket kan orsaka prestandaproblem. Använd endast RegisterClassHandler när programmet kräver att du sparar instanstillståndet.
Ange standardvärdet för ett DependencyProperty under registreringen
När du skapar en DependencyProperty som kräver ett standardvärde anger du värdet med standardmetadata som skickas som en parameter till metoden Register för DependencyProperty. Använd den här tekniken i stället för att ange egenskapsvärdet i en konstruktor eller på varje instans av ett element.
Ställ in egenskapens metadata med hjälp av Register
När du skapar en DependencyPropertykan du ange PropertyMetadata med metoderna Register eller OverrideMetadata. Även om objektet kan ha en statisk konstruktor som anropar OverrideMetadataär detta inte den optimala lösningen och påverkar prestanda. För bästa prestanda anger du PropertyMetadata under anropet till Register.
Frigörbara objekt
En Freezable är en särskild typ av objekt som har två tillstånd: avfryst och frusen. Att frysa objekt när det är möjligt förbättrar programmets prestanda och minskar dess arbetsuppsättning. Mer information finns i Översikt över frysta objekt.
Varje Freezable har en Changed händelse som utlöses när den ändras. Ändringsmeddelanden är dock kostsamma när det gäller programprestanda.
Tänk dig följande exempel där varje Rectangle använder samma Brush objekt:
rectangle_1.Fill = myBrush;
rectangle_2.Fill = myBrush;
rectangle_3.Fill = myBrush;
// ...
rectangle_10.Fill = myBrush;
rectangle_1.Fill = myBrush
rectangle_2.Fill = myBrush
rectangle_3.Fill = myBrush
' ...
rectangle_10.Fill = myBrush
Som standard tillhandahåller WPF en händelsehanterare för SolidColorBrush-objektets Changed händelse för att ogiltigförklara Rectangle-objektets egenskap Fill. I det här fallet, varje gång SolidColorBrush måste utlösa sin Changed-händelse måste den anropa återanropsfunktionen för varje Rectangle– ackumuleringen av dessa anrop innebär en betydande prestandaförsämring. Dessutom är det mycket prestandakrävande att lägga till och ta bort hanterare i det här läget eftersom programmet måste bläddra igenom hela listan för att göra det. Om ditt programscenario aldrig ändrar SolidColorBrushbetalar du kostnaden för att underhålla Changed händelsehanterare i onödan.
Att frysa en Freezable kan förbättra dess prestanda eftersom den inte längre behöver använda resurser för att underhålla ändringsmeddelanden. Tabellen nedan visar storleken på en enkel SolidColorBrush när dess IsFrozen egenskap är inställd på true, jämfört med när den inte är det. Detta förutsätter att du tillämpar en pensel på egenskapen Fill för tio Rectangle objekt.
| Tillstånd | Storlek |
|---|---|
| Frusen SolidColorBrush | 212 byte |
| Ej frusen SolidColorBrush | 972 byte |
Följande kodexempel visar det här konceptet:
Brush frozenBrush = new SolidColorBrush(Colors.Blue);
frozenBrush.Freeze();
Brush nonFrozenBrush = new SolidColorBrush(Colors.Blue);
for (int i = 0; i < 10; i++)
{
// Create a Rectangle using a non-frozed Brush.
Rectangle rectangleNonFrozen = new Rectangle();
rectangleNonFrozen.Fill = nonFrozenBrush;
// Create a Rectangle using a frozed Brush.
Rectangle rectangleFrozen = new Rectangle();
rectangleFrozen.Fill = frozenBrush;
}
Dim frozenBrush As Brush = New SolidColorBrush(Colors.Blue)
frozenBrush.Freeze()
Dim nonFrozenBrush As Brush = New SolidColorBrush(Colors.Blue)
For i As Integer = 0 To 9
' Create a Rectangle using a non-frozed Brush.
Dim rectangleNonFrozen As New Rectangle()
rectangleNonFrozen.Fill = nonFrozenBrush
' Create a Rectangle using a frozed Brush.
Dim rectangleFrozen As New Rectangle()
rectangleFrozen.Fill = frozenBrush
Next i
Ändrade hanterare på Unfrozen Freezables kan hålla objekt vid liv
Ombudet som ett objekt skickar till ett Freezable-objekts Changed-händelse är i praktiken en referens till det objektet. Därför kan Changed händelsehanterare hålla objekt vid liv längre än förväntat. När du rensar ett objekt som har registrerats för att lyssna på ett Freezable objekts Changed händelse är det viktigt att ta bort delegeringen innan objektet släpps.
WPF hanterar också Changed-händelser internt. Till exempel kommer alla beroendeegenskaper som tar Freezable som ett värde automatiskt att lyssna på Changed-händelser. Egenskapen Fill, som antar ett värde av Brush, illustrerar det här konceptet.
Brush myBrush = new SolidColorBrush(Colors.Red);
Rectangle myRectangle = new Rectangle();
myRectangle.Fill = myBrush;
Dim myBrush As Brush = New SolidColorBrush(Colors.Red)
Dim myRectangle As New Rectangle()
myRectangle.Fill = myBrush
Vid tilldelning av myBrush till myRectangle.Fill, kommer en delegering som refererar till Rectangle-objektet att läggas till i SolidColorBrush-objektets Changed-händelse. Det innebär att följande kod inte gör myRect berättigade till skräpinsamling:
myRectangle = null;
myRectangle = Nothing
I det här fallet håller myBrush fortfarande myRectangle vid liv och kommer att anropa den när den utlöser sin Changed-händelse. Observera att om du tilldelar myBrush till egenskapen Fill för en ny Rectangle lägger du helt enkelt till en annan händelsehanterare till myBrush.
Det rekommenderade sättet att rensa dessa typer av objekt är att ta bort Brush från egenskapen Fill, vilket i sin tur tar bort Changed händelsehanterare.
myRectangle.Fill = null;
myRectangle = null;
myRectangle.Fill = Nothing
myRectangle = Nothing
Virtualisering av användargränssnitt
WPF innehåller också en variant av elementet StackPanel som automatiskt "virtualiserar" underordnat innehåll som är databundet. I det här sammanhanget refererar ordet virtualisering till en teknik med vilken en delmängd av objekt genereras från ett större antal dataobjekt baserat på vilka objekt som visas på skärmen. Det är intensivt, både när det gäller minne och processor, att generera ett stort antal gränssnittselement när bara ett fåtal kan finnas på skärmen vid en viss tidpunkt. VirtualizingStackPanel (via funktioner från VirtualizingPanel) beräknar synliga objekt och fungerar med ItemContainerGenerator från en ItemsControl (till exempel ListBox eller ListView) för att endast skapa element för synliga objekt.
Som en prestandaoptimering genereras visuella objekt för dessa objekt endast eller hålls vid liv om de visas på skärmen. När de inte längre finns i kontrollens visningsområde kan de visuella objekten tas bort. Detta ska inte förväxlas med datavirtualisering, där dataobjekt inte alla finns i den lokala samlingen, snarare strömmas in efter behov.
Tabellen nedan visar den förflutna tiden för att lägga till och återge 5000 TextBlock-element till en StackPanel och en VirtualizingStackPanel. I det här scenariot representerar måtten tiden mellan att koppla en textsträng till egenskapen ItemsSource för ett ItemsControl objekt till den tidpunkt då panelelementen visar textsträngen.
| värdpanel | återgivningstid (ms) |
|---|---|
| StackPanel | 3210 |
| VirtualizingStackPanel | 46 |
Se även
.NET Desktop feedback