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 , který systém rozložení využívá, si lze představit jako obdélník, který je rozdělen do rozložení. Třída LayoutInformation vrátí 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í všech omezení, vlastnostmi specifickými pro rozložení (například okraje a odsazení) a individuálním chováním nadřazeného Panel prvku. Zpracování těchto dat, systém rozložení je 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, jako Borderje například , ovlivňují jeho podřízené položky.

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

Screenshot that shows a typical grid, no bounding box superimposed.

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

Screenshot that shows that the TextBlock bounding box is now visible.

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

Slot rozložení se TextBlock přeloží na metodu PathGetLayoutSlot . 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ě rozložení popisuje proces měření a uspořádání členů Panel kolekce prvků Children . Rozložení je náročný proces. Čím větší Children je kolekce, 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 Panel elementem, 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í svoji pozici, může aktivovat nový průchod systémem rozložení. 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. UIElement Dítě zahájí proces rozložení tím, že nejprve změří jeho základní vlastnosti.

  2. Vyhodnocují se vlastnosti určení velikosti definované podle FrameworkElement , například Width, Heighta Margin.

  3. Panel-specifická logika se používá, například Dock směr nebo skládání Orientation.

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

  5. Kolekce Children je nakreslená na obrazovce.

  6. Proces se znovu vyvolá, pokud jsou do kolekce přidány další Children , LayoutTransform je použita nebo UpdateLayout je volána metoda.

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 rozložení dokončí dva průchody pro každého člena Children kolekce, průchod míry a průchod uspořádání. Každé dítě Panel poskytuje své vlastní MeasureOverride a ArrangeOverride metody pro dosažení vlastního specifického chování rozložení.

Během průchodu míry se vyhodnocuje každý člen Children kolekce. Proces začíná voláním Measure metody. Tato metoda je volána v rámci implementace nadřazeného Panel elementu a nemusí být volána explicitně, aby rozložení mohlo dojít.

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

Za druhé, vlastnosti rozhraní definované na FrameworkElement jsou zpracovány, což má vliv na hodnotu constraintSize. Tyto vlastnosti obecně popisují vlastnosti určení velikosti podkladového UIElementobjektu, jako je 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á constraintSize jako parametr.

Poznámka:

Mezi vlastnostmi Height a WidthActualHeight a a ActualWidth. Vlastnost je například ActualHeight počítaná hodnota na základě jiných vstupů výšky a systému rozložení. Hodnota je nastavena samotný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í, například Height, které jsou základem vstupní změny.

Vzhledem k tomu ActualHeight , že se jedná o počítanou hodnotu, 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 přírůstkovým ohlášeným změnám. Systém rozložení může vypočítat požadovaný prostor míry pro podřízené prvky, omezení nadřazeným prvkem atd.

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

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

Metoda ArrangeCore vyhodnotí podřízenou DesiredSize hodnotu a vyhodnotí všechny další okraje, které mohou ovlivnit vykreslenou velikost prvku. ArrangeCore vygeneruje , arrangeSizekterý je předán ArrangeOverride metodě Panel jako parametr. ArrangeOverride vygeneruje finalSize podřízenou. ArrangeCore Metoda nakonec provede konečné vyhodnocení vlastností posunu, jako je okraj a zarovnání, a umístí podřízený prvek do svého 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 objektu a proces rozložení se dokončí.

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

WPF obsahuje skupinu prvků, které jsou odvozeny z Panel. Tyto Panel prvky umožňují mnoho složitých rozložení. Například stacking elementy lze snadno dosáhnout pomocí elementu StackPanel , zatímco složitější a volný tok rozložení jsou možné pomocí Canvas.

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

Název panelu Popis
Canvas Definuje oblast, ve které můžete explicitně umístit podřízené prvky souřadnicemi vzhledem k Canvas oblasti.
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 prvky, 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 horního do dolního nebo pravého doleva v závislosti na hodnotě Orientation vlastnosti.

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

Aspekty výkonu rozložení

Rozložení je rekurzivní proces. Každý podřízený prvek v Children kolekci 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é vodítka o tom, které změny hodnoty vlastnosti 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 naleznete v tématu Přehled vlastností závislostí.

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

    Může LayoutTransform to být velmi užitečný způsob, jak ovlivnit obsah uživatelského rozhraní. Pokud však účinek transformace nemusí mít vliv na pozici jiných prvků, je nejlepší použít RenderTransform místo toho, 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 jistí, že je vyžadována úplná aktualizace, spoléhat se na systém rozložení, který vám tuto metodu zavolá.

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

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

Vykreslování a zaokrouhlování v dílčích pixelech

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ů systému na palec (dpi). 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 považují za rozmazané nebo poloprůhledné hrany, mohou nastat, když místo mezi pixely zařízení spadá umístění okraje uprostřed pixelu zařízení. Systém rozložení nabízí způsob, jak ho upravit pomocí zaokrouhlení rozložení. Zaokrouhlování rozložení je místo, kde systém rozložení zaokrouhluje všechny nenedílnou hodnoty pixelů během průchodu rozložení.

Ve výchozím nastavení je zaokrouhlování rozložení zakázané. Pokud chcete povolit zaokrouhlení rozložení, nastavte UseLayoutRounding vlastnost true na libovolnou FrameworkElementhodnotu . 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 kořenový kontejner. Příklad naleznete v tématu UseLayoutRounding.

Jak 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 Panel prvcích najdete v tématu Přehled panelů. 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 téma Zarovnání, Okraje a Přehled odsazení. Až budete připraveni všechno dát dohromady do jednoduché aplikace, přečtěte si návod : Moje první desktopová aplikace WPF.

Viz také