Dela via


Utformning

I det här avsnittet beskrivs layoutsystemet för Windows Presentation Foundation (WPF). Det är viktigt att förstå hur och när layoutberäkningar sker för att skapa användargränssnitt i WPF.

Det här avsnittet innehåller följande avsnitt:

Begränsningsboxar för element

När du tänker på layout i WPF är det viktigt att förstå avgränsningsrutan som omger alla element. Varje FrameworkElement som används av layoutsystemet kan betraktas som en rektangel som är placerad i layouten. Klassen LayoutInformation returnerar gränserna för ett elements layoutallokering eller fack. Rektangelns storlek bestäms genom beräkning av tillgängligt skärmutrymme, storleken på eventuella begränsningar, layoutspecifika egenskaper (till exempel marginal och utfyllnad) och det överordnade Panel elementets individuella beteende. Vid bearbetning av dessa data kan layoutsystemet beräkna positionen för alla barn i en viss Panel. Det är viktigt att komma ihåg att storleksegenskaper som definierats för det överordnade elementet, till exempel en Border, påverkar dess underordnade element.

Följande bild visar en enkel layout.

Skärmbild som visar ett typiskt rutnät, ingen avgränsningsruta ovanpå.

Den här layouten kan uppnås med hjälp av följande 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>

Ett enda TextBlock element finns i en Grid. Texten fyller bara det övre vänstra hörnet i den första kolumnen, men det allokerade utrymmet för den TextBlock är faktiskt mycket större. Avgränsningsrutan för valfri FrameworkElement kan hämtas genom att använda metoden GetLayoutSlot. Följande bild visar avgränsningsrutan för elementet TextBlock .

Skärmbild som visar att avgränsningsrutan TextBlock nu är synlig.

Som den gula rektangeln visar är det allokerade utrymmet för elementet TextBlock faktiskt mycket större än det verkar. När ytterligare element läggs till i Gridkan den här allokeringen krympa eller expandera, beroende på typ och storlek på element som läggs till.

Layoutplatsen för TextBlock översätts till en Path med hjälp av metoden GetLayoutSlot. Den här tekniken kan vara användbar för att visa begränsningsboxen för ett 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

Layoutsystemet

Som enklast är layout ett rekursivt system som leder till att ett element storleksanpassas, placeras och ritas. Mer specifikt beskriver layout processen för att mäta och ordna medlemmarna i en Panel elementsamling Children . Layout är en intensiv process. Ju större Children samling, desto större är antalet beräkningar som måste göras. Komplexitet kan också introduceras baserat på layoutbeteendet som definieras av elementet Panel som äger samlingen. En relativt enkel Panel, till exempel Canvas, kan ha betydligt bättre prestanda än en mer komplex Panel, till exempel Grid.

Varje gång ett barn UIElement ändrar sin position kan det utlösa en ny genomgång av layoutsystemet. Därför är det viktigt att förstå de händelser som kan anropa layoutsystemet, eftersom onödigt anrop kan leda till sämre programprestanda. Följande beskriver den process som inträffar när layoutsystemet anropas.

  1. Ett barn UIElement påbörjar layoutprocessen genom först att få sina kärnegenskaper mätta.

  2. Storleksegenskaper definierade på FrameworkElement utvärderas, till exempel Width, Height, och Margin.

  3. Panel-specifik logik tillämpas, till exempel Dock riktning eller stapling Orientation.

  4. Innehållet ordnas efter att alla barn har mätts.

  5. Samlingen Children ritas på skärmen.

  6. Processen anropas igen om ytterligare Children läggs till i samlingen, en LayoutTransform tillämpas eller UpdateLayout metoden anropas.

Den här processen och hur den anropas definieras mer detaljerat i följande avsnitt.

Mäta och ordna barn

Layoutsystemet slutför två pass för varje medlem i Children samlingen: ett måttpass och ett ordningspass. Varje barn Panel har sina egna MeasureOverride- och ArrangeOverride-metoder för att uppnå sitt eget specifika layoutbeteende.

Under måttpasset utvärderas varje medlem i Children samlingen. Processen börjar med ett anrop till Measure metoden. Den här metoden anropas inom implementeringen av det överordnade Panel elementet och behöver inte anropas explicit för att layouten ska ske.

Först utvärderas egenskaperna för den UIElement interna storleken, till exempel Clip och Visibility. Detta genererar ett värde med namnet constraintSize som skickas till MeasureCore.

För det andra bearbetas ramverksegenskaper som definierats på FrameworkElement , vilket påverkar värdet för constraintSize. Dessa egenskaper beskriver vanligtvis storleksegenskaperna för den underliggande UIElement, till exempel dess Height, Width, Marginoch Style. Var och en av dessa egenskaper kan ändra det utrymme som krävs för att visa elementet. MeasureOverride anropas sedan med constraintSize som en parameter.

Anmärkning

Det finns en skillnad mellan egenskaperna Height för och Width och ActualHeight och ActualWidth. Egenskapen är till exempel ActualHeight ett beräknat värde baserat på andra höjdindata och layoutsystemet. Värdet anges av själva layoutsystemet, baserat på ett faktiskt återgivningspass, och kan därför ligga något efter det angivna värdet för egenskaper, till exempel , som Heightär grunden för indataändringen.

Eftersom ActualHeight är ett beräknat värde bör du vara medveten om att det kan finnas flera eller inkrementella rapporterade ändringar i det som ett resultat av olika åtgärder av layoutsystemet. Layoutsystemet kan beräkna nödvändigt måttutrymme för underordnade element, begränsningar för det överordnade elementet och så vidare.

Det slutliga målet med måttpasset är att barnet ska fastställa dess DesiredSize, vilket inträffar under anropet MeasureCore . Värdet DesiredSize lagras av Measure för användning under innehållspasset.

Ordna passet börjar med ett anrop till Arrange metoden. Under ordna-passet genererar det överordnade Panel elementet en rektangel som representerar det underordnade objektets gränser. Det här värdet skickas till ArrangeCore metoden för bearbetning.

Metoden ArrangeCore utvärderar det DesiredSize underordnade objektets storlek och utvärderar eventuella ytterligare marginaler som kan påverka elementets renderade storlek. ArrangeCore genererar en arrangeSize, som skickas till ArrangeOverride metoden för Panel som en parameter. ArrangeOverride genererar det finalSize underordnade objektets. Slutligen gör ArrangeCore metoden en slutlig utvärdering av offsetegenskaper, såsom marginal och justering, och placerar barnkomponenten i sin layoutplats. Barnet behöver inte (och fyller ofta inte) hela det allokerade utrymmet. Kontrollen returneras sedan till den överordnade Panel och layoutprocessen är klar.

Panelelement och anpassade layoutbeteenden

WPF innehåller en grupp med element som härleds från Panel. Dessa Panel element möjliggör många komplexa layouter. Du kan till exempel enkelt skapa stackningselement med hjälp av elementet StackPanel , medan mer komplexa och fritt flödande layouter är möjliga med hjälp av en Canvas.

I följande tabell sammanfattas de tillgängliga layoutelementen Panel .

Panelnamn Beskrivning
Canvas Definierar ett område där du uttryckligen kan placera barn efter koordinater i förhållande till Canvas-området.
DockPanel Definierar ett område där du kan ordna barn-element vågrätt eller lodrätt i förhållande till varandra.
Grid Definierar ett flexibelt rutnätsområde som består av kolumner och rader.
StackPanel Ordnar barnobjekt i en linje som kan vara orienterad vågrätt eller lodrätt.
VirtualizingPanel Tillhandahåller ett ramverk för Panel element som virtualiserar deras underliggande datasamling. Det här är en abstrakt klass.
WrapPanel Placerar barn-element i sekventiell position från vänster till höger och bryter innehållet till nästa rad vid kanten av den omslutande rutan. Efterföljande ordning sker sekventiellt uppifrån och ned eller höger till vänster, beroende på egenskapens Orientation värde.

För program som kräver en layout som inte är möjlig med hjälp av något av de fördefinierade Panel elementen kan anpassade layoutbeteenden uppnås genom att ärva från Panel och åsidosätta MeasureOverride metoderna och ArrangeOverride .

Överväganden för layoutprestanda

Layout är en rekursiv process. Varje underordnat element i en Children samling bearbetas under varje anrop av layoutsystemet. Därför bör du undvika att utlösa layoutsystemet när det inte är nödvändigt. Följande överväganden kan hjälpa dig att uppnå bättre prestanda.

  • Tänk på vilka egenskapsvärdeändringar som framtvingar en rekursiv uppdatering av layoutsystemet.

    Beroendeegenskaper vars värden kan göra att layoutsystemet initieras markeras med offentliga flaggor. AffectsMeasure och AffectsArrange ge användbara ledtrådar om vilka egenskapsvärdeändringar som framtvingar en rekursiv uppdatering av layoutsystemet. I allmänhet bör alla egenskaper som kan påverka storleken på en elements avgränsningsbox ha flaggan AffectsMeasure inställd på true. Mer information hittar du i översikt över beroendeegenskaper.

  • När det är möjligt använder du en RenderTransform i stället för en LayoutTransform.

    En LayoutTransform kan vara ett mycket användbart sätt att påverka innehållet i ett användargränssnitt (UI). Men om effekten av transformering inte behöver påverka positionen för andra element, är det bäst att använda en RenderTransform i stället, eftersom RenderTransform inte anropar layoutsystemet. LayoutTransform tillämpar sin transformering och tvingar fram en rekursiv layoutuppdatering för att ta hänsyn till den nya positionen för det berörda elementet.

  • Undvik onödiga anrop till UpdateLayout.

    Metoden UpdateLayout tvingar fram en rekursiv layoutuppdatering och är ofta inte nödvändig. Om du inte är säker på att en fullständig uppdatering krävs måste du använda layoutsystemet för att anropa den här metoden åt dig.

  • När du arbetar med en stor Children samling bör du överväga att använda en VirtualizingStackPanel i stället för en vanlig StackPanel.

    Genom att virtualisera den underordnade samlingen behåller de enda objekten VirtualizingStackPanel i minnet som för närvarande finns i det överordnade objektets ViewPort. Därför förbättras prestanda avsevärt i de flesta scenarier.

Sub-pixel-återgivning och layoutavrundning

WPF-grafiksystemet använder enhetsoberoende enheter för att aktivera upplösning och enhetens oberoende. Varje enhetsoberoende pixel skalas automatiskt med systemets inställning för punkter per tum (dpi). Detta ger WPF-program korrekt skalning för olika dpi-inställningar och gör programmet automatiskt dpi-medveten.

Detta dpi-oberoende kan dock skapa oregelbunden återgivning av kanter på grund av kantutjämning. Dessa artefakter, som vanligtvis ses som suddiga eller halvtransparenta kanter, kan uppstå när platsen för en kant hamnar mitt i en enhetspixel i stället för mellan enhetspixlar. Layoutsystemet erbjuder ett sätt att justera detta problem genom att använda layoutavrundning. Layoutrundning är den plats där layoutsystemet avrundar alla icke-integrerade pixelvärden under layoutpasset.

Layoutrundning är inaktiverad som standard. Om du vill aktivera layoutrundning anger du UseLayoutRounding egenskapen till true på valfri FrameworkElement. Eftersom det är en beroendeegenskap sprids värdet till alla underordnade i det visuella trädet. Om du vill aktivera layoutavrundning för hela användargränssnittet anger du UseLayoutRounding till true på rotcontainern. Ett exempel finns i UseLayoutRounding.

Vad händer nu?

Att förstå hur element mäts och ordnas är det första steget i att förstå layouten. Mer information om tillgängliga element finns Panel i Översikt över paneler. Mer information om de olika positioneringsegenskaperna som kan påverka layouten finns i Justering, Marginaler och Utfyllnadsöversikt. När du är redo att sätta ihop allt i ett lättviktsprogram kan du läsa Genomgång: Mitt första WPF-skrivbordsprogram.

Se även