Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Door inzicht te krijgen in het intrinsieke gedrag van WPF-objecten kunt u de juiste afwegingen maken tussen functionaliteit en prestaties.
Het niet verwijderen van gebeurtenis-handlers op objecten kan objecten actief houden
De afgevaardigde die een object aan zijn gebeurtenis doorgeeft, fungeert effectief als een verwijzing naar dat object. Daarom kunnen gebeurtenis-handlers objecten langer in leven houden dan verwacht. Bij het opschonen van een object dat is geregistreerd om naar de gebeurtenis van een object te luisteren, is het essentieel om die gemachtigde te verwijderen voordat het object wordt vrijgegeven. Als u overbodige objecten actief houdt, neemt het geheugengebruik van de toepassing toe. Dit geldt met name wanneer het object de wortel is van een logische boom of een visuele boom.
WPF introduceert een patroon voor zwakke gebeurtenisluisteraars voor gebeurtenissen die nuttig kunnen zijn in situaties waarin de levensduurrelaties van objecten tussen bron en luisteraar moeilijk te volgen zijn. Sommige bestaande WPF-gebeurtenissen gebruiken dit patroon. Als u objecten met aangepaste gebeurtenissen implementeert, kan dit patroon voor u worden gebruikt. Zie Zwakke gebeurtenispatronen voor meer informatie.
Er zijn verschillende hulpprogramma's, zoals de CLR Profiler en de Werksetviewer, die informatie kan bieden over het geheugengebruik van een opgegeven proces. De CLR Profiler bevat een aantal zeer nuttige weergaven van het toewijzingsprofiel, waaronder een histogram van toegewezen typen, toewijzings- en aanroepgrafieken, een tijdslijn met garbagecollections van verschillende generaties en de resulterende status van de beheerde heap nadat deze verzamelingen plaatsvinden, en een aanroepstructuur met toewijzingen per methode en assembly-ladingen. Zie Performancevoor meer informatie.
Eigenschappen en objecten van afhankelijkheden
Over het algemeen is het openen van een afhankelijkheidseigenschap van een eigenschap DependencyObject niet trager dan het openen van een CLR-eigenschap. Hoewel er een kleine prestatie-overhead is voor het toekennen van een eigenschapswaarde, is het ophalen van een waarde net zo snel als bij een CLR-eigenschap. Het compenseren van de kleine overhead voor prestaties is het feit dat afhankelijkheidseigenschappen robuuste functies ondersteunen, zoals gegevensbinding, animatie, overname en stijl. Zie Overzicht van eigenschappen van afhankelijkhedenvoor meer informatie.
Optimalisaties van afhankelijkheidseigenschappen
U moet afhankelijkheidseigenschappen in uw toepassing zeer zorgvuldig definiëren. Als uw DependencyProperty alleen van invloed is op metagegevensopties voor render type, in plaats van op andere metagegevensopties zoals AffectsMeasure, moet u dit als zodanig markeren door de metagegevens ervan te overschrijven. Zie Metagegevens van afhankelijkheidseigenschappen voor meer informatie over het overschrijven of verkrijgen van metagegevens van eigenschappen.
Het kan efficiënter zijn om een handler voor eigenschapswijzigingen de meting, ordening en weergave handmatig ongeldig te laten maken als niet alle eigenschapswijzigingen daadwerkelijk invloed hebben op deze processen. U kunt bijvoorbeeld besluiten om een achtergrond alleen opnieuw weer te geven wanneer een waarde groter is dan een ingestelde limiet. In dit geval zou de handler van de eigenschapswijziging alleen de rendering ongeldig maken wanneer de waarde de ingestelde limiet overschrijdt.
Het erfbaar maken van een DependencyProperty is niet gratis
Geregistreerde afhankelijkheidseigenschappen kunnen standaard niet worden overgenomen. U kunt echter expliciet instellen dat een eigenschap erfbaar is. Hoewel dit een handige functie is, beïnvloedt het converteren van een eigenschap naar een erfbaar exemplaar de prestaties door de tijdsduur voor het ongeldig maken van eigenschappen te verlengen.
RegisterClassHandler zorgvuldig gebruiken
Tijdens het aanroepen van RegisterClassHandler, kunt u de status van uw exemplaar opslaan. Het is belangrijk te weten dat de handler op elk exemplaar wordt aangeroepen, wat prestatieproblemen kan veroorzaken. RegisterClassHandler Gebruik alleen wanneer uw toepassing vereist dat u de instantiestatus opslaat.
De standaardwaarde instellen voor een DependencyProperty tijdens de registratie
Bij het maken van een DependencyProperty waarde waarvoor een standaardwaarde is vereist, stelt u de waarde in met behulp van de standaardmetagegevens die als parameter worden doorgegeven aan de Register methode van de DependencyProperty. Gebruik deze techniek in plaats van de eigenschapswaarde in te stellen in een constructor of op elk exemplaar van een element.
De PropertyMetadata-waarde instellen met register
Bij het maken van een DependencyProperty, kunt u het PropertyMetadata instellen met behulp van de Register of OverrideMetadata methoden. Hoewel uw object een statische constructor kan hebben om aan te roepen OverrideMetadata, is dit niet de optimale oplossing en heeft dit invloed op de prestaties. Voor de beste prestaties stelt u de PropertyMetadata in tijdens het gesprek met Register.
Invriesbare Objecten
Een Freezable is een speciaal type object met twee statussen: ontrozen en bevroren. Het blokkeren van objecten verbetert waar mogelijk de prestaties van uw toepassing en vermindert de werkset. Zie Overzicht van Freezable Objects voor meer informatie.
Elk Freezable item heeft een Changed gebeurtenis die wordt gegenereerd wanneer deze wordt gewijzigd. Wijzigingsmeldingen zijn echter kostbaar in termen van toepassingsprestaties.
Bekijk het volgende voorbeeld waarin elk Rectangle hetzelfde Brush object gebruikt:
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
WPF biedt standaard een gebeurtenishandler voor de gebeurtenis van SolidColorBrush het Changed object om de eigenschap van Rectangle het Fill object ongeldig te maken. In dit geval geldt dat telkens wanneer de SolidColorBrush zijn Changed gebeurtenis moet activeren, de callback-functie voor iedere Rectangle moet worden aangeroepen. De accumulatie van deze callback-functieaanroepen leidt tot een aanzienlijk prestatieverlies. Daarnaast is het zeer prestatieintensief om op dit moment handlers toe te voegen en te verwijderen, omdat de toepassing hiervoor de hele lijst moet doorlopen. Als uw toepassingsscenario de SolidColorBrush nooit wijzigt, betaalt u onnodig voor het onderhouden van Changed gebeurtenishandlers.
Het blokkeren van een Freezable kan de prestaties verbeteren, omdat er geen resources meer nodig zijn voor het onderhouden van wijzigingsmeldingen. In de onderstaande tabel wordt de grootte getoond van een eenvoudige SolidColorBrush wanneer de IsFrozen eigenschap is ingesteld op true, vergeleken met wanneer dit niet het geval is. Hierbij wordt ervan uitgegaan dat u één kwast toepast op de Fill eigenschap van tien Rectangle objecten.
| Staat | grootte |
|---|---|
| Bevroren SolidColorBrush | 212 Bytes |
| Niet-bevroren SolidColorBrush | 972 bytes |
In het volgende codevoorbeeld ziet u dit concept:
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
Gewijzigde handlers op Unfrozen Freezables kunnen Objecten actief houden
De gedelegeerde die een object doorgeeft aan een Freezable-object's Changed-gebeurtenis, is in feite een verwijzing naar dat object. Changed Daarom kunnen gebeurtenis-handlers objecten langer in leven houden dan verwacht. Bij het opschonen van een object dat is geregistreerd om naar de Freezable gebeurtenis van een Changed object te luisteren, is het essentieel om die delegate te verwijderen voordat het object wordt vrijgegeven.
WPF koppelt Changed ook intern gebeurtenissen aan. Alle afhankelijkheidseigenschappen die als waarde worden gebruikt Freezable , luisteren bijvoorbeeld automatisch naar Changed gebeurtenissen. De Fill eigenschap, die een Brush neemt, illustreert dit concept.
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
Bij de toewijzing van myBrush aan myRectangle.Fill wordt een gedelegeerde die naar het Rectangle object wijst, toegevoegd aan de SolidColorBrush gebeurtenis van het Changed object. Dit betekent dat de volgende code myRect niet in aanmerking laat komen voor garbage collection.
myRectangle = null;
myRectangle = Nothing
In dit geval houdt myBrushmyRectangle nog steeds in leven en zal terugroepen naar myRectangle wanneer zijn -evenement afgaat. Houd er rekening mee dat het toewijzen van myBrush aan de Fill eigenschappen van een nieuwe Rectangle eenvoudigweg een andere gebeurtenishandler toevoegt aan myBrush.
De aanbevolen manier om deze typen objecten op te schonen, is door de BrushFill eigenschap te verwijderen, waardoor de Changed gebeurtenis-handler op zijn beurt wordt verwijderd.
myRectangle.Fill = null;
myRectangle = null;
myRectangle.Fill = Nothing
myRectangle = Nothing
Virtualisatie van gebruikersinterface
WPF biedt ook een variatie van het StackPanel element dat automatisch gegevensgebonden onderliggende inhoud 'virtualiseert'. In deze context verwijst het woord virtualize naar een techniek waarmee een subset van objecten wordt gegenereerd op basis van een groter aantal gegevensitems op basis waarvan items zichtbaar zijn op het scherm. Het is intensief, zowel wat geheugen als processor betreft, om een groot aantal UI-elementen te genereren wanneer slechts enkele elementen op het scherm op een bepaald moment kunnen worden weergegeven. VirtualizingStackPanel (via de functionaliteit die door VirtualizingPanel wordt geleverd) berekent zichtbare elementen en werkt met de ItemContainerGenerator van een ItemsControl (zoals ListBox of ListView) om alleen elementen voor zichtbare items te maken.
Als optimalisatie van prestaties worden visuele objecten voor deze items alleen gegenereerd of actief gehouden als ze zichtbaar zijn op het scherm. Wanneer ze zich niet meer in het weergavegebied van het besturingselement bevinden, kunnen de visuele objecten worden verwijderd. Dit is niet te verwarren met gegevensvirtualisatie, waarbij gegevensobjecten niet allemaal aanwezig zijn in de lokale verzameling, maar waar nodig worden gestreamd.
In de onderstaande tabel ziet u de verstreken tijd voor het toevoegen en weergeven van 5000 TextBlock elementen aan een StackPanel en een VirtualizingStackPanel. In dit scenario vertegenwoordigen de metingen de tijd tussen het koppelen van een tekenreeks aan de ItemsSource eigenschap van een ItemsControl object tot het moment waarop de deelvensterelementen de tekenreeks weergeven.
| Hostpaneel | Weergavetijd (ms) |
|---|---|
| StackPanel | 3210 |
| VirtualizingStackPanel | 46 |
Zie ook
.NET Desktop feedback