Udostępnij przez


Omówienie niestandardowych paneli XAML

Panel to obiekt, który zapewnia układ elementów podrzędnych, gdy uruchamiany jest system układu Rozszerzalnego Języka Znacznika Aplikacji (XAML), a interfejs użytkownika aplikacji jest renderowany.

ważne interfejsy API: Panel, ArrangeOverride, MeasureOverride

Możesz zdefiniować niestandardowe panele dla układu XAML, tworząc klasę niestandardową z klasy Panel . Możesz zapewnić zachowanie panelu, przesłaniając MeasureOverride oraz ArrangeOverride, dostarczając logikę, która mierzy i rozmieszcza elementy podrzędne.

Panel klasy bazowej

Aby zdefiniować niestandardową klasę panelu, można bezpośrednio pochodzić z klasy Panel lub pochodzić z jednej z praktycznych klas paneli, które nie są zapieczętowane, takie jak Grid lub StackPanel. Łatwiej jest wyprowadzać z Panel, ponieważ trudno jest obejść istniejącą logikę układu panelu, który już ma określone zachowanie układu. Ponadto panel z zachowaniem może mieć istniejące właściwości, które nie są istotne dla funkcji układu panelu.

Z panelu , twój panel niestandardowy dziedziczy następujące interfejsy API:

  • Właściwość Dzieci.
  • Właściwości Background, ChildrenTransitions i IsItemsHost oraz identyfikatory właściwości zależności. Żadna z tych właściwości nie jest wirtualna, więc zwykle ich nie przesłaniasz ani nie zastępujesz. Te właściwości nie są zwykle potrzebne w przypadku niestandardowych scenariuszy panelu, nawet w przypadku odczytywania wartości.
  • Metody układu zastępują metody MeasureOverride i ArrangeOverride. Zostały one pierwotnie zdefiniowane przez element FrameworkElement. Klasa panelu podstawowego nie zastępuje tych elementów, ale praktyczne panele takie jak Grid mają implementacje implementowane jako kod natywny i są uruchamiane przez system. Dostarczanie nowych (lub addytujących) implementacji Rozmieszczanieprzestąpiania i MeasureOverride to większość nakładu pracy potrzebnego do zdefiniowania panelu niestandardowego.
  • Wszystkie inne API FrameworkElement, UIElement i DependencyObject, takie jak Height, Visibility i tak dalej. Czasami odwołujesz się do wartości tych właściwości w modyfikacjach układu, ale nie są one wirtualne, więc zazwyczaj ich nie nadpisujesz ani nie zamieniasz.

W tym miejscu skupimy się na opisywaniu pojęć dotyczących układu XAML, dzięki czemu można rozważyć wszystkie możliwości tego, jak panel niestandardowy może i powinien zachowywać się w układzie. Jeśli wolisz przejść bezpośrednio i zobaczyć przykładową niestandardową implementację panelu, zobacz BoxPanel, przykładowy panel niestandardowy.

Właściwość Dzieci

Właściwość Children jest istotna dla panelu niestandardowego, ponieważ wszystkie klasy wywodzące się z Panel używają właściwości Children jako miejsca do przechowywania swoich zawartych elementów podrzędnych w kolekcji. Children jest wyznaczona jako właściwość zawartości XAML dla klasy Panel, a wszystkie klasy pochodzące z Panel mogą dziedziczyć zachowanie tej właściwości. Jeśli właściwość jest oznaczona jako właściwość zawartości XAML, oznacza to, że znaczniki XAML mogą pominąć element właściwości podczas określania tej właściwości w znacznikach, a wartości są ustawiane jako bezpośrednie elementy podrzędne w znacznikach ("zawartość"). Jeśli na przykład utworzysz klasę o nazwie CustomPanel z panelu , która nie definiuje nowego zachowania, nadal możesz użyć tego znacznika:

<local:CustomPanel>
  <Button Name="button1"/>
  <Button Name="button2"/>
</local:CustomPanel>

Gdy analizator XAML odczytuje ten znacznik, Dzieci jest znana jako właściwość zawartości XAML dla wszystkich typów pochodnych Panel, więc analizator doda dwa elementy Button do wartości UIElementCollection właściwości Children. Właściwość zawartości XAML ułatwia uproszczenie relacji rodzic-dziecko w zapisie XAML dla definicji interfejsu użytkownika. Aby uzyskać więcej informacji na temat właściwości zawartości XAML i sposobu wypełniania właściwości kolekcji podczas analizowania kodu XAML, zobacz przewodnik składni XAML.

Typ kolekcji, który utrzymuje wartość właściwości Children, to klasa UIElementCollection. UIElementCollection to silnie typizowana kolekcja, która używa UIElement jako wymuszonego typu elementu. UIElement to typ podstawowy dziedziczony przez setki praktycznych typów elementów interfejsu użytkownika, więc wymuszanie typów w tym miejscu jest celowo luźne. Jednak wymusza to, że nie można mieć Szczotka jako bezpośredni element podrzędny Panel, i ogólnie oznacza to, że tylko elementy, które powinny być widoczne w interfejsie użytkownika i uczestniczyć w układzie, zostaną znalezione jako elementy podrzędne w panelu .

Zazwyczaj niestandardowy panel akceptuje dowolny element podrzędny UIElement zgodnie z definicją XAML, po prostu korzystając z cech właściwości Children as-is. Jako zaawansowany scenariusz można obsługiwać dalsze sprawdzanie typów elementów podrzędnych podczas iterowania kolekcji w przesłonięciach układu.

Oprócz iteracji przez kolekcję Children w nadpisaniach, logika panelu może być również pod wpływem Children.Count. Możesz mieć logikę, która przydziela miejsce co najmniej częściowo na podstawie liczby elementów, a nie żądanych rozmiarów i innych cech poszczególnych elementów.

Zastępowanie metod układu

Podstawowy model metod zastępowania układu (MeasureOverride i ArrangeOverride) polega na tym, że powinny iterować przez wszystkie elementy podrzędne i wywoływać konkretną metodę układu każdego elementu podrzędnego. Pierwszy cykl układu rozpoczyna się, gdy system układu XAML ustawia wizualizację dla okna głównego. Ponieważ każdy element nadrzędny wywołuje rozmieszczenie swoich elementów podrzędnych, propaguje to wywołanie metod rozmieszczania do każdego możliwego elementu interfejsu użytkownika, który ma być częścią rozmieszczenia. W układzie XAML istnieją dwa etapy: miara, a następnie rozmieszczanie.

Nie uzyskujesz żadnego wbudowanego zachowania metody układu dla MeasureOverride i ArrangeOverride z bazowej klasy Panel. Elementy w Dzieci nie będą automatycznie renderowane jako część drzewa wizualnego XAML. To od Ciebie zależy, aby poprzez wywołanie metod układu na każdym z elementów, które znajdziesz w sekcji Dzieci, uczynić te elementy znane procesowi układu, i przeprowadzić je przez układ w ramach Twoich implementacji MeasureOverride oraz ArrangeOverride.

Nie ma powodu, aby wywołać implementacje podstawowe w przesłonięciach układu, chyba że masz własne dziedziczenie. Metody natywne dotyczące zachowania układu (jeśli istnieją) uruchamiają się niezależnie, a pominięcie wywoływania implementacji podstawowej w przesłonięciach nie uniemożliwia ich działania.

Podczas przekazywania miary logika układu wysyła zapytanie do każdego elementu podrzędnego o żądany rozmiar, wywołując metodę Measure dla tego elementu podrzędnego. Wywołanie metody Measure ustawia wartość właściwości DesiredSize . Wartość zwracana MeasureOverride jest żądanym rozmiarem dla samego panelu.

Podczas etapu rozmieszczania pozycje i rozmiary elementów podrzędnych są określane w przestrzeni x-y, a kompozycja układu jest przygotowana do renderowania. Kod musi wywołać Rozmieść dla każdego elementu podrzędnego w Children, aby system układu wykrył, że element należy do układu. Wezwanie Rozmieść jest prekursorem kompozycji i renderowania; informuje system rozmieszczenia, gdzie ma być umieszczony ten element, gdy kompozycja jest gotowa do renderowania.

Wiele właściwości i wartości przyczynia się do działania logiki układu w czasie wykonywania. Sposób myślenia o procesie układu polega na tym, że elementy bez elementów podrzędnych (zazwyczaj najbardziej głęboko zagnieżdżonego elementu w interfejsie użytkownika) to te, które mogą najpierw sfinalizować pomiary. Nie są zależne od elementów podrzędnych, które mają wpływ na ich żądany rozmiar. Mogą mieć własne żądane rozmiary, a są to sugestie dotyczące rozmiaru do momentu rzeczywistego utworzenia układu. Następnie przekazywanie miary kontynuuje się w górę drzewa wizualnego, dopóki element główny nie otrzyma pomiarów, a wszystkie pomiary zostaną sfinalizowane.

Układ kandydata musi mieścić się w bieżącym oknie aplikacji, inaczej niektóre części interfejsu użytkownika zostaną obcięte. Panele często są miejscem, w którym jest określana logika przycięć. Logika panelu może określić, jaki rozmiar jest dostępny w ramach implementacji MeasureOverride i może musieć przekazywać ograniczenia rozmiaru do elementów podrzędnych oraz przydzielać przestrzeń między nie, tak aby wszystko pasowało jak najlepiej. Wynik układu jest idealnym rozwiązaniem, które używa różnych właściwości wszystkich części układu, ale nadal mieści się w oknie aplikacji. Wymaga to zarówno dobrej implementacji logiki układu paneli, jak i rozsądnego projektu interfejsu użytkownika ze strony dowolnego kodu aplikacji, który tworzy interfejs użytkownika przy użyciu tego panelu. Żaden projekt panelu nie będzie wyglądał dobrze, jeśli ogólny projekt interfejsu użytkownika zawiera więcej elementów podrzędnych niż może zmieścić się w aplikacji.

Dużą częścią tego, co sprawia, że system układu działa, jest to, że każdy element oparty na FrameworkElement ma już pewne własne zachowanie związane z działaniem jako element podrzędny w kontenerze. Na przykład istnieje kilka interfejsów API FrameworkElement, które informują o zachowaniu układu albo są konieczne, aby układ w ogóle działał. Są to:

PrzeciążenieMiary

Metoda MeasureOverride ma wartość zwracaną używaną przez system układów jako początkową DesiredSize dla samego panelu, gdy metoda Measure jest wywoływana na panelu przez jego obiekt nadrzędny w układzie. Wybory logiki w metodzie są równie ważne, jak to, co zwraca, a logika często także wpływa na zwracaną wartość.

Wszystkie implementacje MeasureOverride powinny przejść w pętli przez elementy podrzędnei wywołać metodę Measure na każdym elemencie podrzędnym. Wywołanie metody Measure ustawia wartość właściwości DesiredSize . Może to określać, ile miejsca potrzebuje sam panel, a także jak przestrzeń jest podzielona między elementy lub rozmiar konkretnego elementu podrzędnego.

Oto bardzo podstawowy szkielet metody MeasureOverride:

protected override Size MeasureOverride(Size availableSize)
{
    Size returnSize; //TODO might return availableSize, might do something else
     
    //loop through each Child, call Measure on each
    foreach (UIElement child in Children)
    {
        child.Measure(new Size()); // TODO determine how much space the panel allots for this child, that's what you pass to Measure
        Size childDesiredSize = child.DesiredSize; //TODO determine how the returned Size is influenced by each child's DesiredSize
        //TODO, logic if passed-in Size and net DesiredSize are different, does that matter?
    }
    return returnSize;
}

Elementy często mają naturalny rozmiar, gdy są gotowe do układu. Po dokonaniu pomiaru, DesiredSize może wskazywać na rozmiar naturalny, jeśli availableSize przekazany do Measure był mniejszy. Jeśli naturalny rozmiar jest większy niż availableSize, który przekazałeś dla Measure, DesiredSize jest ograniczony do availableSize. Tak właśnie zachowuje się wewnętrzna implementacja miary , a nadpisania układu powinny brać to zachowanie pod uwagę.

Niektóre elementy nie mają naturalnego rozmiaru, ponieważ mają wartości [Auto] dla Height i Width. Te elementy używają pełnej availableSize, ponieważ wartość Auto oznacza dostosowanie rozmiaru elementu do maksymalnie dostępnego, co obiekt nadrzędny układu bezpośrednio komunikuje przez wywołanie Measure za pomocą availableSize. W praktyce zawsze istnieje pewien pomiar, że interfejs użytkownika ma rozmiar do (nawet jeśli jest to okno najwyższego poziomu). W końcu przekazywanie miary rozwiązuje wszystkie wartości auto do ograniczeń nadrzędnych, a wszystkie elementy wartości auto uzyskać rzeczywiste miary (które można uzyskać, sprawdzając ActualWidth i ActualHeight, po zakończeniu układu).

Dopuszczalne jest przekazanie rozmiaru do miary, która ma co najmniej jeden nieskończony wymiar, aby wskazać, że panel może próbować dopasować swój rozmiar, aby zmieścić się w pomiarach jego zawartości. Każdy mierzony element podrzędny ustawia wartość DesiredSize przy użyciu jego naturalnego rozmiaru. Następnie, podczas fazy rozmieszczania, panel zazwyczaj rozmieszcza się, używając tego rozmiaru.

Elementy tekstowe, takie jak TextBlock mają obliczoną ActualWidth i ActualHeight na podstawie ich ciągu tekstowego i właściwości tekstowych, nawet jeśli nie ustawiono wartości Height lub Width, a te wymiary powinny być uwzględniane przez logikę panelu. Przycinanie tekstu to szczególnie zła forma interakcji z interfejsem użytkownika.

Nawet jeśli Twoja implementacja nie wykorzystuje żądanych pomiarów rozmiarów, najlepiej jest wywołać metodę Measure dla każdego elementu podrzędnego, ponieważ istnieją wewnętrzne i natywne zachowania, które są uruchamiane, gdy wywoływana jest Measure. Aby element mógł uczestniczyć w układzie, każdy element podrzędny musi mieć na niego wywołaną metodę Miara w trakcie przebiegu miary oraz metodę Rozmieść w trakcie przebiegu rozmieszczania. Wywołanie tych metod ustawia flagi wewnętrzne na obiekcie i uzupełnia wartości (takie jak właściwość DesiredSize), których potrzebuje logika układu systemu podczas kompilowania drzewa wizualnego oraz renderowania interfejsu użytkownika.

Wartość zwracana MeasureOverride jest oparta na logice panelu interpretującej DesiredSize lub innych zagadnieniach dotyczących rozmiaru dla każdego elementu podrzędnego w , gdy wywoływane jest Measure. Co zrobić z wartościami DesiredSize od elementów podrzędnych oraz jak wykorzystać wartość zwracaną przez MeasureOverride, to kwestia interpretacji twojej własnej logiki. Zazwyczaj nie sumujesz wartości bez modyfikacji, ponieważ dane wejściowe MeasureOverride są często stałym dostępnym rozmiarem sugerowanym przez element nadrzędny panelu. Jeśli przekroczysz ten rozmiar, sam panel może zostać obcięty. Zazwyczaj można porównać całkowity rozmiar elementów podrzędnych z dostępnym rozmiarem panelu i w razie potrzeby wprowadzić korekty.

Porady i wskazówki

  • Najlepiej, aby panel niestandardowy nadawał się na pierwszy rzeczywisty element wizualny w kompozycji interfejsu użytkownika, być może na poziomie bezpośrednio w obszarze Page, UserControl lub innego elementu, który jest elementem głównym strony XAML. W implementacjach MeasureOverride nie zwracaj rutynowo danych wejściowych Size bez badania wartości. Jeśli zwracany Size ma wartość Infinity, może to zgłaszać wyjątki w logice układu środowiska uruchomieniowego. Wartość nieskończoności może pochodzić z głównego okna aplikacji, które można przewijać i dlatego nie ma maksymalnej wysokości. Inne przewijane treści mogą mieć takie samo zachowanie.
  • Innym typowym błędem w implementacjach MeasureOverride jest zwrócenie nowego domyślnego rozmiaru (wartości wysokości i szerokości są 0). Możesz zacząć od tej wartości i może być nawet prawidłową wartością, jeśli panel ustali, że żaden z elementów podrzędnych nie powinien być renderowany. Jednak domyślny Rozmiar powoduje, że panel nie ma właściwego rozmiaru na swoim hoście. Nie wymaga miejsca w interfejsie użytkownika, a zatem nie zajmuje przestrzeni i nie renderuje się. Cały kod panelu może w przeciwnym razie działać prawidłowo, ale nadal nie będzie widoczny panel ani jego zawartość, jeśli składa się z zerowej wysokości, zerowej szerokości.
  • W ramach przesłonięć unikaj pokusy rzutowania elementów podrzędnych na FrameworkElement i korzystaj z właściwości wynikających z układu, w szczególności ActualWidth i ActualHeight. W przypadku najbardziej typowych scenariuszy logikę można opierać na wartości DesiredSize elementu podrzędnego i nie będzie potrzebna żadna z Height ani Width powiązanych właściwości elementu podrzędnego. W przypadku wyspecjalizowanych przypadków, w których znasz typ elementu i masz dodatkowe informacje, na przykład naturalny rozmiar pliku obrazu, możesz użyć wyspecjalizowanych informacji elementu, ponieważ nie jest to wartość, która jest aktywnie zmieniana przez systemy układów. Uwzględnienie właściwości obliczeniowych układu w ramach logiki układu znacznie zwiększa ryzyko definiowania niezamierzonej pętli układu. Pętle te powodują warunek, w którym nie można utworzyć prawidłowego układu, a system może zgłosić wyjątek LayoutCycleException , jeśli pętla nie jest możliwa do odzyskania.
  • Panele zazwyczaj dzielą dostępne miejsce między wieloma elementami podrzędnymi, chociaż dokładny sposób podziału przestrzeni różni się. Na przykład Grid implementuje logikę układu, która używa RowDefinition i wartości ColumnDefinition, aby podzielić przestrzeń na komórki siatki , obsługując zarówno skalowanie gwiazdkowe, jak i wartości pikseli. Jeśli są to wartości pikseli, rozmiar dostępny dla każdego elementu podrzędnego jest już znany, więc jest to, co jest przekazywane jako rozmiar wejściowy dla miary w stylu siatki.
  • Same panele mogą wprowadzać zarezerwowaną przestrzeń do wypełnienia między elementami. Jeśli to zrobisz, upewnij się, że wymiary są widoczne jako właściwość, która różni się od właściwości Margin lub dowolnej właściwości Padding.
  • Elementy mogą mieć wartości dla właściwości ActualWidth i ActualHeight na podstawie wcześniejszego układu. Jeśli wartości się zmieniają, kod interfejsu użytkownika aplikacji może zaimplementować obsługę zdarzeń dla LayoutUpdated na elementach, jeśli istnieje specjalna logika do wykonania, ale zazwyczaj logika panelu nie musi zarządzać zmianami za pomocą obsługi zdarzeń. System układu już określa, kiedy należy ponownie uruchomić układ, ponieważ wartość właściwości odpowiadającej układowi uległa zmianie, a measureOverride panelu lub ArrangeOverride są wywoływane automatycznie w odpowiednich okolicznościach.

RozmieszczaniePrzesłonięcia

Metoda ArrangeOverride ma wartość zwracaną typu Size, która jest używana przez system układu podczas renderowania samego panelu, gdy metoda Arrange jest wywoływana na panelu przez jego element nadrzędny w układzie. Typowe jest, że wejściowe finalSize i zwrócone przez ArrangeOverrideSize są takie same. Jeśli tak nie jest, oznacza to, że panel próbuje ustawić się na inny rozmiar niż ten, który według innych uczestników układu jest dostępny. Ostateczny rozmiar był oparty na tym, że wcześniej uruchamiano przekazywanie miary układu za pośrednictwem kodu panelu, dlatego zwracanie innego rozmiaru nie jest typowe: oznacza to, że celowo ignorujesz logikę miary.

Nie zwracaj rozmiaru ze składnikiem nieskończoności. Próba użycia takiego rozmiaru zgłasza wyjątek z układu wewnętrznego.

Wszystkie implementacje ArrangeOverride powinny przejść przez elementy Childreni wywołać metodę Arrange dla każdego elementu podrzędnego. Podobnie jak Ułożenie, Ułożenie nie ma wartości zwracanej. W przeciwieństwie do miary żadna właściwość obliczeniowa nie jest ustawiana w wyniku (jednak dany element zwykle uruchamia zdarzenie LayoutUpdated ).

Oto bardzo podstawowy szkielet metody ArrangeOverride :

protected override Size ArrangeOverride(Size finalSize)
{
    //loop through each Child, call Arrange on each
    foreach (UIElement child in Children)
    {
        Point anchorPoint = new Point(); //TODO more logic for topleft corner placement in your panel
       // for this child, and based on finalSize or other internal state of your panel
        child.Arrange(new Rect(anchorPoint, child.DesiredSize)); //OR, set a different Size 
    }
    return finalSize; //OR, return a different Size, but that's rare
}

Może dojść do rozmieszczenia układu bez wcześniejszego przeprowadzenia fazy pomiaru. Jednak dzieje się tak tylko wtedy, gdy system układu nie określił żadnych właściwości, które miałyby wpływ na poprzednie pomiary. Na przykład w przypadku zmiany wyrównania nie ma potrzeby ponownego mierzenia tego określonego elementu, ponieważ jego rozmiar DesiredSize nie zmieni się, gdy wybór wyrównania zmieni się. Z drugiej strony, jeśli ActualHeight zmienia się na dowolnym elemencie w układzie, potrzebne jest nowe przeprowadzenie pomiaru. System układu automatycznie wykrywa zmiany rzeczywistej miary i ponownie wywołuje etap mierzenia, a następnie uruchamia kolejny etap rozmieszczania.

Dane wejściowe dla Rozmieszczanie przyjmuje wartość Rect. Najczęstszym sposobem konstruowania tego jest użycie konstruktora, który przyjmuje jako dane wejściowe punkt oraz rozmiar . Punkt to miejsce, w którym należy umieścić lewy górny róg ramki ograniczającej elementu. Rozmiar to wymiary używane do wyświetlania tego określonego elementu. Często używasz DesiredSize dla tego elementu jako wartości Size, ponieważ celem pomiaru układu było ustanowienie DesiredSize dla wszystkich elementów biorących udział w układzie. (Etap miary określa całkowite ustalenie rozmiarów elementów w sposób iteracyjny, dzięki czemu system rozmieszczenia może zoptymalizować sposób umieszczania elementów po osiągnięciu etapu rozmieszczenia).

To, co zwykle różni się w implementacjach ArrangeOverride, to logika, według której panel określa komponent Punkt, jak rozmieszcza każdego elementu podrzędnego. Panel pozycjonowania bezwzględnego, taki jak Canvas, używa jawnych informacji o położeniu pobieranych z każdego elementu za pośrednictwem wartości Canvas.Left oraz Canvas.Top. Panel dzielący przestrzeń, taki jak Grid , miałby operacje matematyczne, które dzieliły dostępne miejsce na komórki, a każda komórka zawierałaby wartość x-y dla miejsca, w którym należy umieścić i rozmieścić jego zawartość. Panel adaptacyjny, taki jak StackPanel, może rozszerzać się tak, aby pasował do zawartości w wymiarze orientacji.

Nadal istnieją dodatkowe wpływy pozycjonowania na elementy w układzie, poza tym, co bezpośrednio kontrolujesz i przekazujesz do Rozmieść. Pochodzą one z wewnętrznej natywnej implementacji klasy Arrange, która jest wspólna dla wszystkich typów pochodnych z FrameworkElement oraz rozszerzona przez niektóre inne typy, takie jak elementy tekstowe. Na przykład elementy mogą mieć margines i wyrównanie, a niektóre z nich mogą mieć wypełnienie. Te właściwości często wchodzą w interakcje. Aby uzyskać więcej informacji, zobacz wyrównanie, margines i wypełnienie.

Panele i elementy sterujące

Unikaj umieszczania funkcji w niestandardowym panelu, który zamiast tego powinien być utworzony jako kontrolka niestandardowa. Rolą panelu jest prezentowanie dowolnej zawartości elementu podrzędnego, która istnieje w niej, jako funkcji układu, która odbywa się automatycznie. Panel może dodawać dekoracje do zawartości (podobnie jak Obramowanie dodaje obramowanie wokół elementu, który prezentuje) lub wykonywać inne dostosowania związane z układem, takie jak wypełnienie. Lecz to jest mniej więcej tyle, na ile należy się posunąć podczas rozszerzania wyników drzewa wizualnego poza raportowanie i wykorzystywanie informacji z elementów podrzędnych.

Jeśli istnieje jakakolwiek interakcja dostępna dla użytkownika, należy napisać kontrolkę niestandardową, a nie panel. Na przykład panel nie powinien dodawać widoków przewijania do prezentowanej zawartości, nawet jeśli celem jest zapobieganie przycinaniu, ponieważ paski przewijania, suwaki itd. są interaktywnymi częściami sterowania. (Zawartość może mieć przecież paski przewijania, ale należy pozostawić to do logiki podrzędnej. Nie wymuszaj jej, dodając przewijanie jako operację układu). Możesz utworzyć kontrolkę, a także napisać panel niestandardowy, który odgrywa ważną rolę w drzewie wizualnym tej kontrolki, jeśli chodzi o prezentowanie zawartości w tej kontrolce. Jednak kontrolka i panel powinny być odrębnymi obiektami kodu.

Jedną z przyczyn różnic między kontrolką a panelem jest to, że jest to spowodowane automatyzacją interfejsu użytkownika firmy Microsoft i ułatwieniami dostępu. Panele zapewniają zachowanie układu wizualnego, a nie zachowanie logiczne. Wygląd elementu interfejsu użytkownika nie jest aspektem interfejsu użytkownika, który jest zwykle ważny dla scenariuszy ułatwień dostępu. Ułatwienia dostępu dotyczą uwidaczniania części aplikacji, które są logicznie ważne dla zrozumienia interfejsu użytkownika. Gdy wymagana jest interakcja, kontrolki powinny uwidocznić możliwości interakcji z infrastrukturą automatyzacji interfejsu użytkownika. Aby uzyskać więcej informacji, zobacz niestandardowe elementy automatyzacji.

Inne API układu

Istnieją inne interfejsy API będące częścią systemu układu, ale nie są deklarowane przez Panel. Można ich używać w implementacji panelu lub w niestandardowej kontrolce korzystającej z paneli.

  • UpdateLayout, InvalidateMeasurei InvalidateArrange to metody, które inicjują przekazywanie układu. InvalidateArrange może nie wyzwolić przebiegu mierzenia, ale dwa pozostałe. Nigdy nie należy wywoływać tych metod z metody przesłonięcia układu, ponieważ niemal na pewno powodują pętlę układu. Kod sterujący zwykle też nie musi ich wywoływać. Większość aspektów układu jest wyzwalana automatycznie, wykrywając zmiany we właściwościach układu zdefiniowanego przez platformę, takich jak Width itd.
  • LayoutUpdated to zdarzenie, które jest uruchamiane, gdy jakiś aspekt układu elementu uległ zmianie. Nie jest to specyficzne dla paneli; zdarzenie jest definiowane przez element FrameworkElement.
  • SizeChanged jest zdarzeniem, które jest uruchamiane tylko po zakończeniu przetwarzania układu i oznacza, że ActualHeight lub ActualWidth uległy zmianie w wyniku. To jest kolejne zdarzenie FrameworkElement . Istnieją przypadki, w których LayoutUpdated uruchamia się, ale SizeChanged nie. Na przykład zawartość wewnętrzna może zostać zmieniona, ale rozmiar elementu nie uległ zmianie.

Referencja

Pojęcia