Delen via


Indeling

In dit onderwerp wordt het WPF-indelingssysteem (Windows Presentation Foundation) beschreven. Begrijpen hoe en wanneer indelingsberekeningen plaatsvinden, is essentieel voor het maken van gebruikersinterfaces in WPF.

Dit onderwerp bevat de volgende secties:

Begrenzingsvakken voor elementen

Wanneer u nadenkt over de indeling in WPF, is het belangrijk om het begrenzingsvak te begrijpen dat alle elementen omringt. Elke FrameworkElement die door het lay-outsysteem wordt gebruikt, kan worden beschouwd als een rechthoek die in de lay-out is geplaatst. De LayoutInformation klasse retourneert de grenzen van de indelingstoewijzing van een element of sleuf. De grootte van de rechthoek wordt bepaald door de beschikbare schermruimte te berekenen, de grootte van beperkingen, indelingsspecifieke eigenschappen (zoals marge en opvulling) en het afzonderlijke gedrag van het bovenliggende Panel element. Door deze gegevens te verwerken, kan het indelingssysteem de positie van alle onderliggende elementen van een bepaalde Panelberekenen. Het is belangrijk om te onthouden dat de afmetingen die zijn gedefinieerd op het bovenliggende element, zoals een Border, van invloed zijn op de kind elementen.

In de volgende afbeelding ziet u een eenvoudige indeling.

Schermopname van een typisch raster, zonder begrenzingsvak.

Deze indeling kan worden bereikt met behulp van de volgende XAML.

<Grid Name="myGrid" Background="LightSteelBlue" Height="150">
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="250"/>
  </Grid.ColumnDefinitions>
  <Grid.RowDefinitions>
    <RowDefinition />
    <RowDefinition />
    <RowDefinition />
  </Grid.RowDefinitions>
  <TextBlock Name="txt1" Margin="5" FontSize="16" FontFamily="Verdana" Grid.Column="0" Grid.Row="0">Hello World!</TextBlock>
  <Button Click="getLayoutSlot1" Width="125" Height="25" Grid.Column="0" Grid.Row="1">Show Bounding Box</Button>
  <TextBlock Name="txt2" Grid.Column="1" Grid.Row="2"/>
</Grid>

Eén TextBlock element wordt gehost binnen een Grid. Hoewel de tekst alleen de linkerbovenhoek van de eerste kolom vult, is de toegewezen ruimte voor de TextBlock eigenlijk veel groter. De beperkingsbox van elke FrameworkElement kan worden verkregen met behulp van de GetLayoutSlot-methode. In de volgende afbeelding ziet u het begrenzingsvak voor het element TextBlock.

Schermopname die laat zien dat het afgebakende vak van de TextBlock nu zichtbaar is.

Zoals wordt weergegeven in de gele rechthoek, is de toegewezen ruimte voor het TextBlock element eigenlijk veel groter dan het lijkt. Naarmate er extra elementen aan de Gridworden toegevoegd, kan deze toewijzing worden verkleind of uitgebreid, afhankelijk van het type en de grootte van elementen die worden toegevoegd.

De indelingssleuf van de TextBlock wordt omgezet in een Path met behulp van de methode GetLayoutSlot. Deze techniek kan handig zijn voor het weergeven van het begrenzingsvak van een element.

private void getLayoutSlot1(object sender, System.Windows.RoutedEventArgs e)
{
    RectangleGeometry myRectangleGeometry = new RectangleGeometry();
    myRectangleGeometry.Rect = LayoutInformation.GetLayoutSlot(txt1);
    Path myPath = new Path();
    myPath.Data = myRectangleGeometry;
    myPath.Stroke = Brushes.LightGoldenrodYellow;
    myPath.StrokeThickness = 5;
    Grid.SetColumn(myPath, 0);
    Grid.SetRow(myPath, 0);
    myGrid.Children.Add(myPath);
    txt2.Text = "LayoutSlot is equal to " + LayoutInformation.GetLayoutSlot(txt1).ToString();
}
Private Sub getLayoutSlot1(ByVal sender As Object, ByVal e As RoutedEventArgs)
    Dim myRectangleGeometry As New RectangleGeometry
    myRectangleGeometry.Rect = LayoutInformation.GetLayoutSlot(txt1)
    Dim myPath As New Path
    myPath.Data = myRectangleGeometry
    myPath.Stroke = Brushes.LightGoldenrodYellow
    myPath.StrokeThickness = 5
    Grid.SetColumn(myPath, 0)
    Grid.SetRow(myPath, 0)
    myGrid.Children.Add(myPath)
    txt2.Text = "LayoutSlot is equal to " + LayoutInformation.GetLayoutSlot(txt1).ToString()
End Sub

Het indelingssysteem

De eenvoudigste indeling is een recursief systeem dat leidt tot de grootte, positie en tekening van een element. Meer specifiek beschrijft indeling het proces van meten en rangschikken van de leden van de Children-verzameling van een Panel-element. Indeling is een intensief proces. Hoe groter de verzameling Children, hoe groter het aantal berekeningen dat moet worden gemaakt. Complexiteit kan ook worden geïntroduceerd op basis van het lay-outgedrag dat is gedefinieerd door het Panel element dat eigenaar is van de verzameling. Een relatief eenvoudige Panel, zoals Canvas, kan aanzienlijk betere prestaties hebben dan een complexere Panel, zoals Grid.

Telkens wanneer een kind UIElement zijn positie wijzigt, kan het een nieuwe doorgang activeren van het indelingssysteem. Daarom is het belangrijk om inzicht te hebben in de gebeurtenissen die het indelingssysteem kunnen aanroepen, omdat onnodige aanroep kan leiden tot slechte toepassingsprestaties. Hieronder wordt het proces beschreven dat optreedt wanneer het indelingssysteem wordt aangeroepen.

  1. Een kindelement UIElement begint het indelingsproces door eerst zijn kerneigenschappen te laten meten.

  2. De grootte-eigenschappen die zijn gedefinieerd op FrameworkElement worden geëvalueerd, zoals Width, Heighten Margin.

  3. Panel-specifieke logica wordt toegepast, zoals Dock richting of Orientationstapelen.

  4. Inhoud wordt gerangschikt nadat alle kinderen zijn gemeten.

  5. De Children collectie wordt getekend op het scherm.

  6. Het proces wordt opnieuw aangeroepen als er extra Children worden toegevoegd aan de verzameling, een LayoutTransform wordt toegepast of de UpdateLayout methode wordt aangeroepen.

Dit proces en hoe het wordt aangeroepen, worden gedetailleerder gedefinieerd in de volgende secties.

Kinderen meten en rangschikken

Het indelingssysteem voltooit twee passen voor elk element van de Children-verzameling: een meetpas en een rangschikkingspas. Elk kind Panel biedt zijn eigen MeasureOverride en ArrangeOverride methoden voor specifiek lay-outgedrag.

Tijdens de meetpassage wordt elk lid van de Children collectie geëvalueerd. Het proces begint met een aanroep naar de methode Measure. Deze methode wordt aangeroepen binnen de implementatie van het bovenliggende Panel element en hoeft niet expliciet te worden aangeroepen om de indeling uit te voeren.

Ten eerste worden de native grootte-eigenschappen van de UIElement geëvalueerd, zoals Clip en Visibility. Hiermee wordt een waarde gegenereerd met de naam constraintSize die wordt doorgegeven aan MeasureCore.

Ten tweede worden frameworkeigenschappen die zijn gedefinieerd op FrameworkElement verwerkt, wat van invloed is op de waarde van constraintSize. Deze eigenschappen beschrijven in het algemeen de dimensiekenmerken van de onderliggende UIElement, zoals de Height, Width, Marginen Style. Elk van deze eigenschappen kan de ruimte wijzigen die nodig is om het element weer te geven. MeasureOverride wordt vervolgens aangeroepen met constraintSize als parameter.

Notitie

Er is een verschil tussen de eigenschappen van Height en Width en ActualHeight en ActualWidth. De eigenschap ActualHeight is bijvoorbeeld een berekende waarde op basis van andere hoogte-invoer en het indelingssysteem. De waarde wordt ingesteld door het indelingssysteem zelf, op basis van een werkelijke renderingspas, en kan daarom iets achterblijven bij de setwaarde van eigenschappen, zoals Height, die de basis zijn van de invoerwijziging.

Omdat ActualHeight een berekende waarde is, moet u er rekening mee houden dat er meerdere of incrementele gerapporteerde wijzigingen kunnen zijn als gevolg van verschillende bewerkingen door het indelingssysteem. Het indelingssysteem kan de benodigde maatruimte berekenen voor onderliggende elementen, beperkingen opgelegd door het bovenliggende element, enzovoort.

Het uiteindelijke doel van het doorvoeren van de maatregel is dat het kind zijn DesiredSizebepaalt, wat plaatsvindt tijdens het MeasureCore oproepen. De DesiredSize-waarde wordt door Measure opgeslagen voor gebruik tijdens de inrichtingspas voor content.

De rangschikkenpas begint met een aanroep van de methode Arrange. Tijdens de indelingsfase genereert het bovenliggende Panel-element een rechthoek die de grenzen van het kind-element vertegenwoordigt. Deze waarde wordt doorgegeven aan de ArrangeCore-methode voor verwerking.

De methode ArrangeCore evalueert de DesiredSize van het kind en beoordeelt eventuele extra marges die de weergegeven grootte van het element kunnen beïnvloeden. ArrangeCore genereert een arrangeSize, die als parameter wordt doorgegeven aan de ArrangeOverride methode van de Panel. ArrangeOverride genereert de finalSize van het kind. Ten slotte voert de methode ArrangeCore een definitieve evaluatie uit van offseteigenschappen, zoals marge en uitlijning, en plaatst het kind in het lay-outslot. Het kind hoeft de volledige toegewezen ruimte niet te vullen (en vaak niet). De controle wordt vervolgens teruggegeven aan de ouder Panel en het indelingsproces is voltooid.

Paneelelementen en gedrag van aangepaste indeling

WPF bevat een groep elementen die zijn afgeleid van Panel. Deze Panel elementen maken veel complexe indelingen mogelijk. Het stapelen van elementen kan bijvoorbeeld eenvoudig worden bereikt met behulp van het StackPanel element, terwijl complexere en vrije indelingen mogelijk zijn met behulp van een Canvas.

De volgende tabel bevat een overzicht van de beschikbare indeling Panel elementen.

Paneelnaam Beschrijving
Canvas Hiermee definieert u een gebied waarin u subelementen expliciet kunt positioneren op coördinaten ten opzichte van het gebied Canvas.
DockPanel Definieert een gebied waarin u kindelementen horizontaal of verticaal kunt rangschikken ten opzichte van elkaar.
Grid Definieert een flexibel rastergebied dat bestaat uit kolommen en rijen.
StackPanel Rangschikt kindelementen in één lijn die horizontaal of verticaal kan worden georiënteerd.
VirtualizingPanel Biedt een framework voor Panel-elementen die de gegevensverzameling van hun kinderen virtualiseren. Dit is een abstracte klasse.
WrapPanel Plaatst onderliggende elementen in sequentiële positie van links naar rechts, waarbij inhoud wordt onderbroken naar de volgende regel aan de rand van het inhoudsvak. Volgende volgorde vindt opeenvolgend plaats van boven naar beneden of van rechts naar links, afhankelijk van de waarde van de eigenschap Orientation.

Voor toepassingen waarvoor een indeling vereist is die niet mogelijk is met behulp van een van de vooraf gedefinieerde Panel elementen, kunnen aangepaste indelingsgedragen worden bereikt door het overnemen van Panel en het overschrijven van de MeasureOverride- en ArrangeOverride methoden.

Overwegingen voor lay-outprestaties

Indeling is een recursief proces. Elk kind-element in een Children-verzameling wordt verwerkt tijdens elke aanroep van het indelingssysteem. Als gevolg hiervan moet het activeren van het indelingssysteem worden vermeden wanneer dit niet nodig is. De volgende overwegingen kunnen u helpen betere prestaties te bereiken.

  • Let op welke wijzigingen in de eigenschapswaarde een recursieve update door het indelingssysteem afdwingen.

    Afhankelijkheidseigenschappen waarvan de waarden ertoe kunnen leiden dat het indelingssysteem wordt geïnitialiseerd, worden gemarkeerd met openbare vlaggen. AffectsMeasure en AffectsArrange nuttige aanwijzingen geven over welke wijzigingen in de eigenschapswaarde een recursieve update door het indelingssysteem afdwingen. Over het algemeen moet voor elke eigenschap die van invloed kan zijn op de grootte van het begrenzingsvak van een element de AffectsMeasure-vlag op 'waar' staan. Zie Overzicht van eigenschappen van afhankelijkhedenvoor meer informatie.

  • Gebruik indien mogelijk een RenderTransform in plaats van een LayoutTransform.

    Een LayoutTransform kan een zeer nuttige manier zijn om de inhoud van een gebruikersinterface (UI) te beïnvloeden. Als het effect van de transformatie echter niet van invloed is op de positie van andere elementen, kunt u het beste een RenderTransform gebruiken, omdat RenderTransform het indelingssysteem niet aanroept. LayoutTransform de transformatie toepast en een recursieve indelingsupdate dwingt om rekening te houden met de nieuwe positie van het betrokken element.

  • Vermijd onnodige aanroepen naar UpdateLayout.

    De methode UpdateLayout dwingt een recursieve indelingsupdate af en is vaak niet nodig. Tenzij u zeker weet dat een volledige update vereist is, moet u vertrouwen op het indelingssysteem om deze methode voor u aan te roepen.

  • Wanneer u met een grote Children verzameling werkt, kunt u overwegen een VirtualizingStackPanel te gebruiken in plaats van een gewone StackPanel.

    Door de kindverzameling te virtualiseren, houdt de VirtualizingStackPanel alleen objecten in het geheugen die zich momenteel in de ViewPort van de bovenliggende ouder bevinden. Hierdoor worden de prestaties in de meeste scenario's aanzienlijk verbeterd.

Afronding van sub pixelweergave en indeling

Het WPF-grafische systeem maakt gebruik van apparaatonafhankelijke eenheden om resolutie en apparaatonafhankelijkheid mogelijk te maken. Elke apparaatonafhankelijke pixel wordt automatisch geschaald met de dpi-instelling (dots per inch) van het systeem. Dit biedt WPF-toepassingen de juiste schaalaanpassing voor verschillende dpi-instellingen en maakt de toepassing automatisch dpi-bewust.

Deze dpi-onafhankelijkheid kan echter onregelmatige edge-rendering maken vanwege antialiassen. Deze artefacten, meestal gezien als wazige of semitransparante randen, kunnen optreden wanneer de locatie van een rand midden in een apparaat pixel valt in plaats van tussen apparaat pixels. Het indelingssysteem biedt een manier om dit aan te passen met layoutronding. Met indelingsafronding worden alle niet-integrale pixelwaarden tijdens de lay-outpass afgerond.

Indelingsronding is standaard uitgeschakeld. Als u het afronden van de indeling wilt inschakelen, stelt u de eigenschap UseLayoutRounding in op true op elke FrameworkElement. Omdat het een afhankelijkheidseigenschap is, wordt de waarde doorgegeven aan alle onderliggende elementen in de visuele boom. Als u het afronden van de indeling voor de hele gebruikersinterface wilt inschakelen, stelt u UseLayoutRounding in op true op de hoofdcontainer. Zie UseLayoutRoundingvoor een voorbeeld.

Wat is de volgende stap?

Begrijpen hoe elementen worden gemeten en gerangschikt, is de eerste stap bij het begrijpen van de indeling. Zie Panels Overviewvoor meer informatie over de beschikbare Panel elementen. Zie Overzicht van uitlijning, marges en opvullingvoor meer inzicht in de verschillende plaatsingseigenschappen die van invloed kunnen zijn op de indeling. Wanneer u klaar bent om alles samen te voegen in een lichtgewicht toepassing, raadpleegt u Walkthrough: Mijn eerste WPF-bureaubladtoepassing.

Zie ook