Układ

W tym temacie opisano system układu programu Windows Presentation Foundation (WPF). Zrozumienie, jak i kiedy występują obliczenia układu, jest niezbędne do tworzenia interfejsów użytkownika w WPF.

Ten temat zawiera następujące sekcje:

Pola ograniczenia elementów

Podczas myślenia o układzie w WPF ważne jest, aby zrozumieć pole ograniczenia, które otacza wszystkie elementy. Każdy FrameworkElement używany przez system układu może być uważany za prostokąt, który jest umieszczany w układzie. Klasa LayoutInformation zwraca granice alokacji układu elementu lub miejsca. Rozmiar prostokąta zależy od obliczenia dostępnego miejsca na ekranie, rozmiaru wszelkich ograniczeń, właściwości specyficznych dla układu (takich jak margines i wypełnienie) oraz indywidualnego zachowania elementu nadrzędnego Panel . Przetwarzanie tych danych pozwala systemowi układu obliczyć położenie wszystkich elementów podrzędnych określonego Panelelementu . Należy pamiętać, że cechy rozmiaru zdefiniowane dla elementu nadrzędnego, takie jak Border, wpływają na jego elementy podrzędne.

Poniższa ilustracja przedstawia prosty układ.

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

Ten układ można osiągnąć przy użyciu następującego kodu 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>

Pojedynczy TextBlock element jest hostowany w obiekcie Grid. Chociaż tekst wypełnia tylko lewy górny róg pierwszej kolumny, przydzielone miejsce dla elementu TextBlock jest w rzeczywistości znacznie większe. Pole ograniczenia dowolnego FrameworkElement elementu można pobrać przy użyciu GetLayoutSlot metody . Poniższa ilustracja przedstawia pole ograniczenia dla TextBlock elementu.

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

Jak pokazano na żółtym prostokątie, przydzielone miejsce dla TextBlock elementu jest w rzeczywistości znacznie większe niż się wydaje. W miarę dodawania Griddodatkowych elementów do tej alokacji można zmniejszyć lub rozwinąć, w zależności od typu i rozmiaru dodanych elementów.

Miejsce układu obiektu TextBlock jest tłumaczone na Path element przy użyciu GetLayoutSlot metody . Ta technika może być przydatna do wyświetlania pola ograniczenia elementu.

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

System układu

W najprostszym układzie jest rekursywny system, który prowadzi do rozmiaru, położenia i narysowania elementu. W szczególności układ opisuje proces mierzenia i rozmieszczania elementów członkowskich Panel kolekcji elementu Children . Układ jest procesem intensywnie korzystającym. Im większa kolekcja, tym większa Children liczba obliczeń, które należy wykonać. Złożoność można również wprowadzić na podstawie zachowania układu zdefiniowanego Panel przez element, który jest właścicielem kolekcji. Stosunkowo proste Panel, takie jak Canvas, może mieć znacznie lepszą wydajność niż bardziej złożone Panel, takie jak Grid.

Za każdym razem, gdy element podrzędny UIElement zmienia swoją pozycję, może wyzwolić nowe przekazanie przez system układu. Dlatego ważne jest, aby zrozumieć zdarzenia, które mogą wywołać system układu, ponieważ niepotrzebne wywołanie może prowadzić do niskiej wydajności aplikacji. Poniżej opisano proces, który występuje po wywołaniu systemu układu.

  1. Element podrzędny UIElement rozpoczyna proces układu, najpierw mając mierzone podstawowe właściwości.

  2. Właściwości określania rozmiaru zdefiniowane na są FrameworkElement oceniane, takie jak Width, Heighti Margin.

  3. Panel-specyficzna logika jest stosowana, na przykład Dock kierunek lub stos Orientation.

  4. Zawartość jest rozmieszczana po zmierzeniu wszystkich elementów podrzędnych.

  5. Kolekcja Children jest rysowana na ekranie.

  6. Proces jest wywoływany ponownie w przypadku dodania dodatkowego Children do kolekcji, LayoutTransform zastosowania metody lub wywołania UpdateLayout metody.

Ten proces i sposób jego wywoływani są definiowane bardziej szczegółowo w poniższych sekcjach.

Mierzenie i rozmieszczanie elementów podrzędnych

System układu kończy dwa przebiegi dla każdego elementu członkowskiego Children kolekcji, przebiegu miary i przebiegu rozmieszczania. Każde dziecko Panel udostępnia własne MeasureOverride metody i ArrangeOverride w celu osiągnięcia własnego zachowania układu.

Podczas przekazywania miary każdy element członkowski kolekcji Children jest oceniany. Proces rozpoczyna się od wywołania Measure metody . Ta metoda jest wywoływana w implementacji elementu nadrzędnego Panel i nie musi być wywoływana jawnie w celu wystąpienia układu.

Najpierw są oceniane właściwości rozmiaru UIElement natywnego, takie jak Clip i Visibility. Spowoduje to wygenerowanie wartości o nazwie constraintSize przekazanej do MeasureCoreelementu .

Po drugie, właściwości struktury zdefiniowane na FrameworkElement są przetwarzane, co wpływa na wartość constraintSize. Te właściwości zazwyczaj opisują cechy rozmiaru bazowego UIElement, takie jak jego Height, Width, Margini Style. Każda z tych właściwości może zmienić miejsce niezbędne do wyświetlenia elementu. MeasureOverride parametr jest następnie wywoływany za pomocą constraintSize parametru .

Uwaga

Istnieje różnica między właściwościami Height i i Width i ActualHeightActualWidth. Na przykład ActualHeight właściwość jest wartością obliczeniową opartą na innych danych wejściowych wysokości i systemie układu. Wartość jest ustawiana przez sam system układu na podstawie rzeczywistego przebiegu renderowania i dlatego może nieznacznie opóźnić się od ustawionej wartości właściwości, takich jak Height, które są podstawą zmiany wejściowej.

Ponieważ ActualHeight jest to wartość obliczeniowa, należy pamiętać, że może istnieć wiele lub przyrostowych zgłoszonych zmian w nim w wyniku różnych operacji przez system układu. System układu może obliczać wymaganą przestrzeń miary dla elementów podrzędnych, ograniczeń według elementu nadrzędnego itd.

Ostatecznym celem przebiegu miary jest określenie elementu DesiredSizepodrzędnego , który występuje podczas wywołania MeasureCore . Wartość DesiredSize jest przechowywana do Measure użycia podczas rozmieszczania zawartości.

Przekazywanie rozmieszczania rozpoczyna się od wywołania Arrange metody . Podczas przekazywania rozmieszczania element nadrzędny Panel generuje prostokąt reprezentujący granice elementu podrzędnego. Ta wartość jest przekazywana do metody przetwarzania ArrangeCore .

Metoda ArrangeCore oblicza DesiredSize element podrzędny i ocenia wszelkie dodatkowe marginesy, które mogą mieć wpływ na renderowany rozmiar elementu. ArrangeCore generuje element arrangeSize, który jest przekazywany do ArrangeOverride metody Panel jako parametru. ArrangeOverride generuje finalSize element podrzędny. ArrangeCore Na koniec metoda wykonuje ostateczną ocenę właściwości przesunięcia, takich jak margines i wyrównanie, i umieszcza element podrzędny w jego miejscu układu. Dziecko nie musi (a często nie) wypełnia całe przydzielone miejsce. Kontrolka zostanie następnie zwrócona do elementu nadrzędnego Panel , a proces układu zostanie ukończony.

Elementy panelu i niestandardowe zachowania układu

WPF zawiera grupę elementów, które pochodzą z Panel. Te Panel elementy umożliwiają wiele złożonych układów. Na przykład elementy stosu można łatwo osiągnąć za pomocą StackPanel elementu, natomiast bardziej złożone i wolne układy przepływające są możliwe przy użyciu elementu Canvas.

Poniższa tabela zawiera podsumowanie dostępnych elementów układu Panel .

Nazwa panelu opis
Canvas Definiuje obszar, w którym można jawnie ustawić elementy podrzędne według współrzędnych względem Canvas obszaru.
DockPanel Definiuje obszar, w którym można rozmieścić elementy podrzędne w poziomie lub w pionie względem siebie.
Grid Definiuje elastyczny obszar siatki składający się z kolumn i wierszy.
StackPanel Rozmieszcza elementy podrzędne w jedną linię, która może być zorientowana w poziomie lub w pionie.
VirtualizingPanel Zapewnia strukturę elementów Panel wirtualizujących zbieranie danych podrzędnych. Jest to abstrakcyjna klasa.
WrapPanel Umieszcza elementy podrzędne w pozycji sekwencyjnej od lewej do prawej, powodując niezgodność zawartości do następnego wiersza na krawędzi pola zawierającego. Kolejność następuje sekwencyjnie od góry do dołu lub od prawej do lewej Orientation , w zależności od wartości właściwości.

W przypadku aplikacji wymagających układu, który nie jest możliwy przy użyciu żadnego ze wstępnie zdefiniowanych Panel elementów, zachowania układu niestandardowego można osiągnąć, dziedzicząc i Panel przesłaniając MeasureOverride metody i ArrangeOverride .

Zagadnienia dotyczące wydajności układu

Układ jest procesem rekursywnym. Każdy element podrzędny w Children kolekcji jest przetwarzany podczas każdego wywołania systemu układu. W związku z tym należy unikać wyzwalania systemu układu, gdy nie jest to konieczne. Poniższe zagadnienia mogą pomóc w lepszej wydajności.

  • Należy pamiętać, które zmiany wartości właściwości wymuszą rekursywną aktualizację systemu układu.

    Właściwości zależności, których wartości mogą spowodować zainicjowanie systemu układu, są oznaczone flagami publicznymi. AffectsMeasure i AffectsArrange podaj przydatne wskazówki dotyczące tego, które zmiany wartości właściwości wymuszą rekursywną aktualizację przez system układu. Ogólnie rzecz biorąc, każda właściwość, która może mieć wpływ na rozmiar pola ograniczenia elementu, powinna mieć flagę ustawioną AffectsMeasure na true. Aby uzyskać więcej informacji, zobacz Właściwości zależności — omówienie.

  • Jeśli to możliwe, użyj elementu RenderTransform zamiast .LayoutTransform

    Może LayoutTransform to być bardzo przydatny sposób wpływania na zawartość interfejsu użytkownika. Jeśli jednak efekt przekształcenia nie musi mieć wpływu na położenie innych elementów, najlepiej użyć RenderTransform elementu zamiast, ponieważ RenderTransform nie wywołuje systemu układu. LayoutTransform stosuje transformację i wymusza aktualizację układu cyklicznego, aby uwzględnić nowe położenie elementu, którego dotyczy problem.

  • Unikaj niepotrzebnych wywołań do .UpdateLayout

    Metoda UpdateLayout wymusza aktualizację układu cyklicznego i często nie jest konieczna. Jeśli nie masz pewności, że wymagana jest pełna aktualizacja, należy opierać się na systemie układu, aby wywołać tę metodę.

  • Podczas pracy z dużą Children kolekcją rozważ użycie elementu VirtualizingStackPanel zamiast zwykłego StackPanel.

    Wirtualizacja kolekcji podrzędnej powoduje zachowanie VirtualizingStackPanel tylko obiektów w pamięci, które znajdują się obecnie w obiekcie nadrzędnym ViewPort. W związku z tym wydajność jest znacznie większa w większości scenariuszy.

Renderowanie pod pikselami i zaokrąglanie układu

System graficzny WPF używa jednostek niezależnych od urządzeń, aby umożliwić rozpoznawanie i niezależność urządzeń. Każdy niezależny piksel urządzenia jest automatycznie skalowany przy użyciu ustawienia kropek na cal (dpi). Zapewnia to odpowiednie skalowanie aplikacji WPF dla różnych ustawień dpi i sprawia, że aplikacja automatycznie obsługuje dpi.

Jednak ta niezależność dpi może tworzyć nieregularne renderowanie krawędzi ze względu na anty aliasy. Te artefakty, zwykle postrzegane jako rozmyte lub półprzezroczyste krawędzie, mogą wystąpić, gdy lokalizacja krawędzi spadnie w środku piksela urządzenia zamiast między pikselami urządzenia. System układu umożliwia dostosowanie tego układu za pomocą zaokrąglania układu. Zaokrąglanie układu polega na tym, że układ zaokrągla wszystkie nieuliczne wartości pikseli podczas przekazywania układu.

Zaokrąglanie układu jest domyślnie wyłączone. Aby włączyć zaokrąglanie układu, ustaw właściwość na true dowolną UseLayoutRoundingFrameworkElementwartość . Ponieważ jest to właściwość zależności, wartość będzie propagowana do wszystkich elementów podrzędnych w drzewie wizualizacji. Aby włączyć zaokrąglanie układu dla całego interfejsu użytkownika, ustaw wartość UseLayoutRounding na true w kontenerze głównym. Przykład można znaleźć w temacie UseLayoutRounding.

Co dalej?

Zrozumienie, jak elementy są mierzone i rozmieszczane, to pierwszy krok w zrozumieniu układu. Aby uzyskać więcej informacji na temat dostępnych Panel elementów, zobacz Panele — omówienie. Aby lepiej zrozumieć różne właściwości pozycjonowania, które mogą mieć wpływ na układ, zobacz Wyrównanie, Marginesy i Omówienie wypełnienia. Gdy wszystko będzie gotowe do zebrania w lekkiej aplikacji, zobacz Przewodnik: Moja pierwsza aplikacja klasyczna WPF.

Zobacz też