Sdílet prostřednictvím


Rozložení

Toto téma popisuje systém rozložení WPF (Windows Presentation Foundation). Pochopení způsobu a výskytu výpočtů rozložení je nezbytné pro vytváření uživatelských rozhraní ve WPF.

Toto téma obsahuje následující části:

Ohraničující rámečky prvků

Při zvažování rozložení ve WPF je důležité pochopit ohraničující rámeček, který obklopuje všechny prvky. Každý FrameworkElement spotřebovaný systémem rozložení si můžete představit jako obdélník, který je zasazený do rozložení. Třída LayoutInformation vrací hranice přidělení rozložení elementu nebo slotu. Velikost obdélníku je určena výpočtem dostupného místa na obrazovce, velikostí jakýchkoli omezení, vlastnostmi specifických pro rozložení (například okraje a odsazení) a individuálním chováním nadřazeného Panel prvku. Při zpracování těchto dat je systém uspořádání schopen vypočítat pozici všech podřízených položek určitého Panel. Je důležité si uvědomit, že vlastnosti velikosti definované u nadřazeného prvku například Borderovlivňují jeho potomky.

Následující obrázek znázorňuje jednoduché rozložení.

Snímek obrazovky, který ukazuje typickou mřížku, bez ohraničujícího rámečku.

Toto rozložení lze dosáhnout pomocí následujícího kódu 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>

Jeden prvek TextBlock je hostovaný v Grid. Zatímco text vyplní pouze levý horní roh prvního sloupce, přidělené místo pro TextBlock je ve skutečnosti mnohem větší. Ohraničující rámeček libovolného FrameworkElement lze načíst pomocí metody GetLayoutSlot. Následující obrázek znázorňuje ohraničující rámeček pro prvek TextBlock.

Snímek obrazovky, který ukazuje, že ohraničení textového bloku je teď viditelné.

Jak je znázorněno žlutým obdélníkem, přidělený prostor pro prvek TextBlock je ve skutečnosti mnohem větší, než se zobrazuje. Při přidání dalších prvků do Gridse může toto přidělení zmenšit nebo zvětšit v závislosti na typu a velikosti přidaných prvků.

Slot rozložení TextBlock je přeložen na Path pomocí metody GetLayoutSlot. Tato technika může být užitečná pro zobrazení ohraničujícího rámečku prvku.

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

Systém rozložení

V nejjednodušším rozložení je rekurzivní systém, který vede k velikosti, umístění a vykreslení prvku. Konkrétně rozvržení popisuje proces měření a uspořádání členů kolekce prvku PanelChildren. Rozložení je náročný proces. Čím větší je kolekce Children, tím větší je počet výpočtů, které je potřeba provést. Složitost lze také zavést na základě chování rozložení definovaného elementem Panel, který vlastní kolekci. Relativně jednoduchý Panel, například Canvas, může mít výrazně lepší výkon než složitější Panel, například Grid.

Pokaždé, když dítě UIElement změní svou pozici, může to aktivovat nový průchod systémem uspořádání. Proto je důležité pochopit události, které mohou vyvolat systém rozložení, protože zbytečné vyvolání může vést k nízkému výkonu aplikace. Následující článek popisuje proces, ke kterému dochází při vyvolání systému rozložení.

  1. Dítě UIElement zahájí proces rozložení tím, že se nejprve změří jeho základní vlastnosti.

  2. Vlastnosti velikosti definované na FrameworkElement se vyhodnocují, například Width, Heighta Margin.

  3. Panelse aplikuje logika specifická pro určité prvky, jako je směr Dock nebo stacking Orientation.

  4. Obsah se uspořádá po měření všech podřízených položek.

  5. Kolekce Children je nakreslena na obrazovce.

  6. Proces se znovu vyvolá, pokud se do kolekce přidají další Children, použije se LayoutTransform nebo se volá metoda UpdateLayout.

Tento proces a způsob jeho vyvolání jsou podrobněji definovány v následujících částech.

Měření a uspořádání dětí

Systém rozvržení dokončí dva průchody pro každého člena kolekce Children, měřicí průchod a uspořádávací průchod. Každý podřízený Panel poskytuje své vlastní MeasureOverride a ArrangeOverride metody pro dosažení vlastního specifického chování rozložení.

Během průchodu měření se vyhodnocuje každý člen kolekce Children. Proces začíná voláním metody Measure. Tato metoda je volána v rámci implementace nadřazeného elementu Panel a není nutné ji volat explicitně, aby došlo k rozvržení.

Nejprve se vyhodnotí nativní vlastnosti velikosti UIElement, například Clip a Visibility. Tím se vygeneruje hodnota s názvem constraintSize, která se předá MeasureCore.

Za druhé se zpracovávají vlastnosti rozhraní definované na FrameworkElement, které ovlivňují hodnotu constraintSize. Tyto vlastnosti obecně popisují charakteristiky velikosti podkladového UIElement, například jeho Height, Width, Margina Style. Každá z těchto vlastností může změnit prostor, který je nutný k zobrazení prvku. MeasureOverride se pak volá s constraintSize jako parametrem.

Poznámka

Mezi vlastnostmi Height a Width a ActualHeight a ActualWidthexistuje rozdíl. Například vlastnost ActualHeight je počítaná hodnota na základě jiných vstupů výšky a systému rozložení. Hodnota je nastavena vlastním systémem rozložení na základě skutečného průchodu vykreslování, a proto může mírně zaostávat za nastavenou hodnotou vlastností, jako je Height, které jsou základem vstupní změny.

Vzhledem k tomu, že ActualHeight je počítaná hodnota, měli byste vědět, že v důsledku různých operací systému rozložení může dojít k několika nebo postupným změnám. Systém rozložení může vypočítat potřebný měřící prostor pro podřízené prvky, omezení nadřazeného prvku atd.

Konečným cílem měřícího průchodu je, aby dítě určilo svůj DesiredSize, které se vyskytuje během MeasureCore volání. Hodnota DesiredSize je uložena Measure pro použití během uspořádání obsahu.

Předání uspořádání začíná voláním metody Arrange. Během fáze uspořádání nadřazený prvek Panel vygeneruje obdélník, který představuje hranice podřízeného prvku. Tato hodnota se předá metodě ArrangeCore ke zpracování.

Metoda ArrangeCore vyhodnotí DesiredSize podřízeného objektu a vyhodnotí všechny další okraje, které mohou ovlivnit vykreslenou velikost prvku. ArrangeCore vygeneruje arrangeSize, který je předán jako parametr metodě ArrangeOverride v Panel. ArrangeOverride vygeneruje finalSize dítěte. Nakonec metoda ArrangeCore provede konečné vyhodnocení vlastností posunu, jako je okraj a zarovnání, a umístí podřízený prvek do jeho slotu rozložení. Dítě nemusí (a často nevyplňuje) celý přidělený prostor. Ovládací prvek se pak vrátí do nadřazeného Panel a proces rozložení se dokončí.

Prvky panelu a vlastní chování rozložení

WPF obsahuje skupinu prvků odvozených z Panel. Tyto prvky Panel umožňují mnoho složitých rozložení. Například stohování prvků lze snadno docílit pomocí prvku StackPanel, zatímco složitější a volně plynoucí rozvržení je možné díky Canvas.

Následující tabulka shrnuje dostupné elementy rozložení Panel.

Název panelu Popis
Canvas Definuje oblast, ve které můžete přesně umístit dceřiné prvky podle souřadnic vzhledem k oblasti Canvas.
DockPanel Definuje oblast, ve které můžete uspořádat podřízené prvky vodorovně nebo svisle vzhledem k sobě.
Grid Definuje flexibilní oblast mřížky, která se skládá ze sloupců a řádků.
StackPanel Uspořádá podřízené prvky na jednu čáru, která může být orientována vodorovně nebo svisle.
VirtualizingPanel Poskytuje architekturu pro Panel elementy, které virtualizují jejich podřízené shromažďování dat. Toto je abstraktní třída.
WrapPanel Umístí podřízené prvky do sekvenční pozice zleva doprava a rozdělí obsah na další řádek na okraji obsahujícího pole. Následné řazení probíhá postupně od shora dolů nebo zprava doleva v závislosti na hodnotě vlastnosti Orientation.

U aplikací, které vyžadují rozložení, které není možné pomocí předdefinovaných prvků Panel, lze vlastní chování rozložení dosáhnout děděním z Panel a přepsáním MeasureOverride a ArrangeOverride metod.

Aspekty výkonu rozložení

Rozložení je rekurzivní proces. Každý podřízený prvek v kolekci Children se zpracuje během každého vyvolání systému rozložení. V důsledku toho by se mělo zabránit aktivaci systému rozložení, pokud to není nutné. Následující aspekty vám můžou pomoct dosáhnout lepšího výkonu.

  • Mějte na paměti, která změna hodnoty vlastnosti vynutí rekurzivní aktualizaci systémem rozložení.

    Vlastnosti závislosti, jejichž hodnoty mohou způsobit inicializaci systému rozložení, jsou označené veřejnými příznaky. AffectsMeasure a AffectsArrange poskytují užitečné informace o tom, které změny hodnot vlastností vynutí rekurzivní aktualizaci systému rozložení. Obecně platí, že jakákoli vlastnost, která může ovlivnit velikost ohraničujícího rámečku prvku, by měla mít AffectsMeasure příznak nastaven na hodnotu true. Další informace najdete v tématu Přehled vlastností závislosti.

  • Pokud je to možné, použijte místo LayoutTransformRenderTransform .

    LayoutTransform může být velmi užitečným způsobem, jak ovlivnit obsah uživatelského rozhraní. Pokud však účinek transformace nemusí mít vliv na pozici jiných prvků, je nejlepší místo toho použít RenderTransform, protože RenderTransform nevyvolá systém rozložení. LayoutTransform použije transformaci a vynutí aktualizaci rekurzivního rozložení tak, aby zohlednila nové umístění ovlivněného prvku.

  • Vyhněte se zbytečným voláním UpdateLayout.

    Metoda UpdateLayout vynutí rekurzivní aktualizaci rozložení a často není nutná. Pokud si nejste jisti, že je vyžadována úplná aktualizace, spoléhejte na systém rozložení, který tuto metodu zavolá za vás.

  • Při práci s velkou kolekcí Children zvažte použití VirtualizingStackPanel místo běžného StackPanel.

    Virtualizací podřízené kolekce VirtualizingStackPanel uchovává pouze objekty v paměti, které jsou aktuálně v objektu ViewPort nadřazeného objektu. V důsledku toho se ve většině scénářů výrazně vylepšuje výkon.

Vykreslování pomocí dílčích pixelů a zaokrouhlování rozvržení

Grafický systém WPF používá jednotky nezávislé na zařízeních k povolení rozlišení a nezávislosti zařízení. Každý pixel nezávislý na zařízení se automaticky škáluje s nastavením bodů na palec (dpi) systému. To poskytuje aplikacím WPF správné škálování pro různá nastavení dpi a umožňuje aplikaci automaticky rozpoznat dpi.

Tato nezávislost dpi ale může vytvořit nepravidelné vykreslování okrajů z důvodu anti-aliasingu. Tyto artefakty, které se obvykle jeví jako rozmazané nebo poloprůhledné hrany, mohou nastat, když umístění hrany spadá do středu pixelu zařízení místo mezi pixely zařízení. Systém rozložení nabízí způsob, jak ho upravit pomocí zaokrouhlení rozložení. Zaokrouhlování rozložení je proces, kdy systém rozložení zaokrouhluje všechny necelé hodnoty pixelů během procesu rozložení.

Ve výchozím nastavení je zaokrouhlování rozložení zakázané. Pokud chcete povolit zaokrouhlování rozložení, nastavte vlastnost UseLayoutRounding na true v libovolném FrameworkElement. Protože se jedná o vlastnost závislosti, hodnota se rozšíří do všech podřízených položek ve vizuálním stromu. Pokud chcete povolit zaokrouhlování rozložení pro celé uživatelské rozhraní, nastavte UseLayoutRounding na true v kořenovém kontejneru. Příklad viz UseLayoutRounding.

Co dál

Pochopení způsobu měření a uspořádání prvků je prvním krokem při pochopení rozložení. Další informace o dostupných prvcích Panel naleznete v tématu Panely – přehled. Pokud chcete lépe porozumět různým vlastnostem umístění, které můžou mít vliv na rozložení, přečtěte si Přehled zarovnání, okrajů a odsazení. Až budete připraveni dát vše dohromady v odlehčené aplikaci, přečtěte si Návod: Moje první desktopová aplikace WPF.

Viz také