Udostępnij za pomocą


Rozszerzenia znaczników i WPF XAML

W tym temacie przedstawiono koncepcję rozszerzeń znaczników dla języka XAML, w tym ich reguły składniowe, przeznaczenie oraz model klasowy obiektów, który stanowi podstawę dla tych rozszerzeń. Rozszerzenia znaczników (markup extensions) to ogólna funkcja języka XAML i implementacji usług XAML w platformie .NET. W tym temacie szczegółowo opisano rozszerzenia znaczników do używania w WPF XAML.

Procesory XAML i rozszerzenia znaczników

Ogólnie rzecz biorąc, analizator XAML może interpretować wartość atrybutu jako dosłowny ciąg znaków, który można przekonwertować na typ prymitywny, lub przekonwertować go na obiekt różnymi metodami. Jednym z takich środków jest odwoływanie się do konwertera typów; Jest to udokumentowane w temacie TypeConverters i XAML. Istnieją jednak scenariusze, w których wymagane jest różne zachowanie. Na przykład procesor XAML może być poinstruowany, że wartość atrybutu nie powinna spowodować nowego obiektu na grafie obiektów. Zamiast tego atrybut powinien spowodować wykres obiektu, który tworzy odwołanie do już skonstruowanego obiektu w innej części grafu lub obiektu statycznego. Innym scenariuszem jest to, że procesor XAML może być poinstruowany, aby użyć składni, która dostarcza argumenty inne niż domyślne do konstruktora obiektu. Są to typy scenariuszy, w których rozszerzenie znaczników może zapewnić rozwiązanie.

Podstawowa składnia rozszerzenia znaczników

Rozszerzenie znaczników można zaimplementować, aby dostarczać wartości dla właściwości w kontekście użycia atrybutu, właściwości w kontekście użycia elementu właściwości lub obu.

W przypadku podania wartości atrybutu, procesor XAML rozpoznaje sekwencję rozszerzenia znaczników dzięki obecności nawiasów klamrowych ({ i }). Typ rozszerzenia znaczników jest następnie identyfikowany przez ciąg znaków reprezentujący token, znajdujący się bezpośrednio po otwarciu nawiasu klamrowego.

W przypadku użycia w składni elementu właściwości rozszerzenie znaczników jest wizualnie takie samo jak każdy inny element używany do podania wartości elementu właściwości: deklaracja elementu XAML, która odwołuje się do klasy rozszerzenia znaczników jako elementu, ujętego w nawiasy kątowe (<>).

XAML-Defined Rozszerzenia znaczników

Istnieje kilka rozszerzeń znaczników, które nie są specyficzne dla implementacji XAML w WPF, lecz są implementacjami wewnętrznych cech lub funkcji XAML jako języka. Te rozszerzenia znaczników są implementowane w zestawie System.Xaml w ramach ogólnych usług XAML programu .NET Framework i znajdują się w przestrzeni nazw języka XAML. Jeśli chodzi o typowe użycie znaczników, te rozszerzenia znaczników są zwykle możliwe do zidentyfikowania przez prefiks x:. MarkupExtension Klasa bazowa (zdefiniowana również w System.Xaml) udostępnia wzorzec, którego powinny używać wszystkie rozszerzenia znaczników w celu obsługi przez czytniki XAML i pisarzy XAML, w tym w systemie WPF XAML.

Uwaga / Notatka

Prefiks x: jest używany do typowego mapowania przestrzeni nazw XAML w elemencie głównym pliku XAML lub przy tworzeniu plików XAML. Na przykład szablony programu Visual Studio dla aplikacji WPF inicjują plik XAML przy użyciu tego x: mapowania. Możesz wybrać inny token prefiksu w swoim własnym mapowaniu przestrzeni nazw XAML, ale w tej dokumentacji zakłada się domyślne mapowanie x: jako sposób identyfikacji tych elementów, które są zdefiniowaną częścią przestrzeni nazw XAML, w przeciwieństwie do domyślnej przestrzeni nazw WPF lub innych przestrzeni nazw XAML, które nie są związane z określoną platformą.

WPF-Specific Rozszerzenia znaczników

Najbardziej typowe rozszerzenia znaczników używane w programowaniu WPF to te, które obsługują odwołania do zasobów (StaticResource i ), oraz DynamicResourcete, które obsługują powiązanie danych (Binding).

  • StaticResource dostarcza wartość dla właściwości, zastępując wartość już zdefiniowanego zasobu. Ocena StaticResource jest ostatecznie wykonana w czasie ładowania XAML i nie ma dostępu do grafu obiektów w czasie wykonywania. Aby uzyskać szczegółowe informacje, zobacz StaticResource Markup Extension (Rozszerzenie znaczników staticResource).

  • DynamicResource zapewnia wartość dla właściwości, odkładając jej określenie na czas wykonania jako odniesienie do zasobu. Dynamiczne odwołanie do zasobu wymusza nowe wyszukiwanie za każdym razem, gdy taki zasób jest odczytywany, i ma dostęp do grafu obiektów w czasie wykonywania. Aby uzyskać ten dostęp, koncepcja DynamicResource jest wspierana przez właściwości zależności w systemie właściwości WPF i oceniane wyrażenia. W związku z tym można używać DynamicResource tylko dla obiektu docelowego właściwości zależności. Aby uzyskać szczegółowe informacje, zobacz DynamicResource Markup Extension (Rozszerzenie znaczników dynamicResource).

  • Binding udostępnia wartość powiązaną z danymi dla właściwości, przy użyciu kontekstu danych, który wiąże się z obiektem nadrzędnym w czasie wykonywania. To rozszerzenie znaczników jest stosunkowo złożone, ponieważ umożliwia znaczącą składnię śródliniową określania powiązania danych. Aby uzyskać szczegółowe informacje, zobacz Rozszerzenie Znaczników Powiązań.

  • RelativeSource dostarcza informacji źródłowych dla elementu Binding, który może nawigować między różnymi relacjami w drzewie obiektów podczas wykonywania. Zapewnia to wyspecjalizowane określanie źródła powiązań utworzonych w szablonach z wieloma użyciemi lub utworzonych w kodzie bez pełnej wiedzy o otaczającym drzewie obiektów. Aby uzyskać szczegółowe informacje, zobacz RelativeSource MarkupExtension.

  • TemplateBinding Umożliwia szablonowi kontrolki używanie wartości dla właściwości szablonów pochodzących z właściwości zdefiniowanych przez model obiektów klasy, która będzie używać szablonu. Innymi słowy, właściwość w definicji szablonu może uzyskać dostęp do kontekstu, który istnieje tylko po zastosowaniu szablonu. Aby uzyskać szczegółowe informacje, zobacz TemplateBinding Markup Extension (Rozszerzenie znaczników TemplateBinding). Aby uzyskać więcej informacji na temat praktycznego użycia elementu TemplateBinding, zobacz Styling with ControlTemplates Sample.

  • ColorConvertedBitmap obsługuje stosunkowo zaawansowany scenariusz tworzenia obrazów. Aby uzyskać szczegółowe informacje, zobacz ColorConvertedBitmap Markup Extension (Rozszerzenie znaczników mapy ColorConvertedBitmap).

  • ComponentResourceKey i ThemeDictionary obsługują aspekty wyszukiwania zasobów, szczególnie w przypadku zasobów i motywów, które są pakowane za pomocą kontrolek niestandardowych. Aby uzyskać więcej informacji, zobacz ComponentResourceKey Markup Extension, ThemeDictionary Markup Extension lub Control Authoring Overview (Omówienie tworzenia kontrolek).

*Klasy rozszerzeń

Dla ogólnego języka XAML i rozszerzeń znaczników specyficznych dla WPF, zachowanie każdego rozszerzenia jest identyfikowane przez procesor XAML poprzez klasę *Extension, która dziedziczy z MarkupExtension i zapewnia implementację metody ProvideValue. Ta metoda dla każdego rozszerzenia udostępnia obiekt zwracany podczas oceniania rozszerzenia znaczników. Zwrócony obiekt jest zazwyczaj oceniany na podstawie różnych elementów ciągów przekazywanych do rozszerzenia znaczników.

Na przykład klasa StaticResourceExtension zapewnia rzeczywistą implementację przeszukiwania zasobów, dzięki czemu jej implementacja ProvideValue zwraca żądany obiekt. Dane wejściowe tej konkretnej implementacji są ciągiem znaków używanym do przeszukiwania zasobu według x:Key. Wiele z tych szczegółów implementacji jest nieważne, jeśli używasz istniejącego rozszerzenia znaczników.

Niektóre rozszerzenia znaczników nie używają argumentów związanych z ciągiem znaków. Jest to spowodowane tym, że zwracają wartość statyczną lub spójną albo kontekst dla zwracanej wartości jest dostępny za pośrednictwem jednej z usług przekazywanych przez serviceProvider parametr .

Wzorzec *Extension nazewnictwa jest przeznaczony dla wygody i spójności. Nie jest konieczne, aby procesor XAML zidentyfikował tę klasę jako rozszerzenie znaczników. Tak długo, jak baza kodu zawiera system.Xaml i używa implementacji usług XAML programu .NET Framework, wszystko, co jest konieczne, aby być rozpoznawane jako rozszerzenie znaczników XAML, to pochodzić z MarkupExtension i obsługiwać składnię konstrukcji. WPF definiuje klasy umożliwiające rozszerzenia znaczników, które nie są zgodne ze wzorcem nazewnictwa *Extension, na przykład Binding. Zazwyczaj przyczyną jest to, że klasa obsługuje scenariusze poza czystą obsługą rozszerzenia znaczników. W przypadku Bindingklasy ta obsługuje dostęp w czasie wykonywania do metod i właściwości obiektu dla scenariuszy, które nie mają nic wspólnego z językiem XAML.

Interpretacja klasy rozszerzenia dla tekstu inicjalizacji

Tokeny ciągów następujące po nazwie rozszerzenia znaczników i nadal w klamrach są interpretowane przez procesor XAML na jeden z następujących sposobów:

  • Przecinek zawsze reprezentuje separator lub ogranicznik poszczególnych tokenów.

  • Jeśli oddzielne tokeny nie zawierają żadnych znaków równości, każdy token jest traktowany jako argument konstruktora. Każdy parametr konstruktora musi być podany jako typ oczekiwany przez ten podpis i w odpowiedniej kolejności oczekiwanej przez ten podpis.

    Uwaga / Notatka

    Procesor XAML musi wywołać konstruktor, który odpowiada liczbie par argumentów. Z tego powodu, jeśli implementujesz niestandardowe rozszerzenie znaczników, nie twórz wielu konstruktorów z tą samą liczbą argumentów. Zachowanie sposobu działania procesora XAML, jeśli istnieje więcej niż jedna ścieżka konstruktora rozszerzenia znaczników o tej samej liczbie parametrów, nie jest zdefiniowana, ale należy przewidzieć, że procesor XAML może zgłosić wyjątek użycia, jeśli ta sytuacja istnieje w definicjach typu rozszerzenia znaczników.

  • Jeśli poszczególne oddzielone tokeny zawierają znaki równości, procesor XAML najpierw wywołuje konstruktor bez parametrów dla rozszerzenia znaczników. Następnie każda para name=value jest interpretowana jako nazwa właściwości, która istnieje w rozszerzeniu znaczników, i wartość do przypisania do tej właściwości.

  • Jeśli istnieje równoległy wynik między zachowaniem konstruktora a zachowaniem ustawienia właściwości w rozszerzeniu znaczników, to nie ma znaczenia, którego zachowania używasz. Częściej używa się par właściwości=wartości dla rozszerzeń znaczników, które mają więcej niż jedną właściwość do ustawienia, choćby dlatego, że znacznik jest bardziej celowy i jest mniej prawdopodobne, aby przypadkowo zamienić miejscami parametry konstruktora. (Zdefiniowane pary właściwość=wartość mogą być w dowolnej kolejności). Ponadto nie ma gwarancji, że rozszerzenie znaczników dostarcza parametr konstruktora, który ustawia wszystkie jego dostępne do ustawienia właściwości. Na przykład Binding jest rozszerzeniem znaczników, z wieloma właściwościami, które można ustawić za pośrednictwem rozszerzenia w formularzu właściwość=wartość, ale Binding obsługuje tylko dwa konstruktory: konstruktor bez parametrów i jeden, który ustawia początkową ścieżkę.

  • Nie można przekazać przecinka literału do rozszerzenia znaczników bez ucieczki.

Sekwencje ucieczki i rozszerzenia znaczników

Obsługa atrybutów w procesorze XAML używa nawiasów klamrowych jako wskaźników sekwencji rozszerzeń znaczników. Jest również możliwe utworzenie wartości atrybutu z dosłownym znakiem nawiasu klamrowego w razie potrzeby, wprowadzając sekwencję ucieczki przy użyciu pustej pary nawiasów klamrowych, a następnie dodając dosłowny nawias klamrowy. Zobacz {} Sekwencja ucieczki — rozszerzenie znaczników.

Zagnieżdżanie rozszerzeń znaczników w użyciu języka XAML

Obsługiwane jest gniazdowanie wielu rozszerzeń znaczników, a każde rozszerzenie znaczników będzie oceniane zaczynając od najgłębszego. Rozważmy na przykład następujące użycie:

<Setter Property="Background"
  Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" />

W tym użyciu instrukcja x:Static jest oceniana jako pierwsza i zwraca ciąg. Ten ciąg jest następnie używany jako argument dla elementu DynamicResource.

Rozszerzenia znaczników i składnia elementu właściwości

W przypadku użycia jako elementu obiektu, który wypełnia wartość elementu właściwości, klasa rozszerzenia znaczników jest wizualnie nie do odróżnienia od typowego elementu obiektu, który może być używany w języku XAML. Praktyczna różnica między typowym elementem obiektu a rozszerzeniem znaczników polega na tym, że rozszerzenie znaczników jest przetwarzane do typowanej wartości lub odłożone jako wyrażenie. W związku z tym mechanizmy wszelkich możliwych błędów typów wartości właściwości dla rozszerzenia składniowego będą różne, podobnie jak w przypadku, gdy właściwość wiązana późno jest traktowana w innych modelach programowania. Zwykły element obiektu zostanie oceniony pod kątem dopasowania typu do właściwości docelowej, która jest ustawiana podczas analizowania kodu XAML.

Większość rozszerzeń znaczników, używanych w składni elementu obiektu do wypełniania elementu właściwości, nie ma zawartości ani żadnej dalszej składni elementu właściwości. W ten sposób można zamknąć tag elementu obiektu i zapewnić brak elementów podrzędnych. Za każdym razem, gdy dowolny element obiektu jest napotkany przez procesor XAML, konstruktor dla tej klasy jest wywoływany, który tworzy wystąpienie obiektu utworzonego na podstawie przeanalizowanego elementu. Klasa rozszerzenia znaczników nie różni się: jeśli rozszerzenie znaczników ma być używane w składni elementu obiektu, musisz podać konstruktor bez parametrów. Niektóre istniejące rozszerzenia znaczników mają co najmniej jedną wymaganą wartość właściwości, która musi być określona dla skutecznego inicjowania. Jeśli tak, ta wartość właściwości jest zwykle podawana jako atrybut właściwości w elemecie object. W referencyjnych stronach Funkcje językowe przestrzeni nazw XAML (x:) oraz rozszerzeniach XAML WPF, rozszerzenia znaczników, które mają wymagane właściwości (oraz nazwy wymaganych właściwości), zostaną zanotowane. Strony referencyjne będą również zwracać uwagę, jeśli składnia elementu obiektu lub składnia atrybutu jest niedozwolona dla określonych rozszerzeń znaczników. Godny uwagi przypadek to x:Array Markup Extension, które nie może obsługiwać składni atrybutów, ponieważ zawartość tej tablicy musi być określona w tagowaniu jako zawartość. Zawartość tablicy jest obsługiwana jako obiekty ogólne, dlatego nie można wykonać domyślnego konwertera typów dla atrybutu. Ponadto rozszerzenie x:Array Markup wymaga parametru type .

Zobacz także