Udostępnij za pośrednictwem


Omówienie rozszerzeń znaczników dla języka XAML

Rozszerzenia znaczników to technika XAML umożliwiająca uzyskiwanie wartości, które nie są typami pierwotnymi ani określonymi typami XAML. W przypadku użycia atrybutów rozszerzenia znaczników korzystają z dobrze znanej sekwencji znaków: otwierający nawias klamrowy { rozpoczyna zakres rozszerzenia znaczników, a zamykający nawias klamrowy } go kończy. W przypadku korzystania z usług XAML platformy .NET można użyć niektórych wstępnie zdefiniowanych rozszerzeń znaczników języka XAML z zestawu System.Xaml. Możesz również podklasę z klasy MarkupExtension zdefiniowanej w pliku System.Xaml i zdefiniować własne rozszerzenia znaczników. Możesz też użyć rozszerzeń znaczników zdefiniowanych przez określoną platformę, jeśli już odwołujesz się do tej platformy.

Gdy uzyskiwany jest dostęp do użycia rozszerzenia znaczników, moduł zapisywania obiektów XAML może udostępniać usługi niestandardowej klasie MarkupExtension przez punkt połączenia usługi w przesłonięciu MarkupExtension.ProvideValue. Usługi mogą służyć do uzyskiwania kontekstu użycia, określonych możliwości modułu zapisywania obiektów, kontekstu schematu XAML itd.

Rozszerzenia znaczników zdefiniowane przez język XAML

Kilka rozszerzeń znaczników jest implementowanych przez usługi .NET XAML na potrzeby obsługi języka XAML. Te rozszerzenia znaczników odpowiadają częściom specyfikacji języka XAML jako języka. Są one zwykle możliwe do zidentyfikowania przez prefiks x: w składni, jak pokazano we wspólnym użyciu. Implementacje usług XAML platformy .NET dla tych elementów języka XAML pochodzą z klasy bazowej MarkupExtension.

Notatka

Prefiks x: jest używany do typowego mapowania przestrzeni nazw XAML języka w elemencie głównym dokumentu XAML. Na przykład szablony projektów i stron programu Visual Studio dla różnych określonych struktur inicjują plik XAML przy użyciu tego mapowania x:. Możesz wybrać inny token prefiksu we własnym mapowaniu przestrzeni nazw XAML, ale ta dokumentacja zakłada domyślne mapowanie x: jako sposób identyfikacji tych jednostek, które są zdefiniowaną częścią przestrzeni nazw XAML języka XAML, w przeciwieństwie do domyślnej przestrzeni nazw XAML określonej platformy lub innych dowolnych przestrzeni nazw CLR lub XML.

x:Type

x:Type dostarcza obiekt Type dla nazwanego typu. Ta funkcja jest używana najczęściej w mechanizmach odroczenia, które używają bazowego typu CLR i wyprowadzania typu jako nazwy grupowania lub identyfikatora. Style i szablony WPF oraz ich użycie właściwości TargetType są konkretnym przykładem. Aby uzyskać więcej informacji, zobacz x:Type Markup Extension.

x:Static

x:Static tworzy wartości statyczne z jednostek kodu typu wartości, które nie są bezpośrednio typem wartości właściwości, ale mogą być oceniane dla tego typu. Jest to przydatne w przypadku określania wartości, które już istnieją, jak również znanych stałych w definicji typu. Aby uzyskać więcej informacji, zobacz x:Static Markup Extension.

x:Null

x:Null określa null jako wartość członka XAML. W zależności od projektu określonych typów lub większych koncepcji struktury null nie zawsze jest wartością domyślną właściwości lub implikaną wartością pustego atrybutu ciągu. Aby uzyskać więcej informacji, zobacz x:Null Markup Extension.

x:Array

x:Array obsługuje tworzenie ogólnych tablic w składni XAML w przypadkach, gdy obsługa kolekcji zapewniana przez elementy podstawowe i modele sterowania nie jest celowo używana. Aby uzyskać więcej informacji, zobacz x:Array Markup Extension. W XAML 2009 tablice są traktowane jako pierwotne elementy języka, a nie jako rozszerzenie. Aby uzyskać więcej informacji, zobacz funkcje języka XAML 2009 .

x:Reference

x:Reference jest częścią zestawu języków XAML 2009, rozszerzenia oryginalnego zestawu języków (2006). x:Reference reprezentuje odwołanie do innego istniejącego obiektu w grafie obiektu. Ten obiekt jest identyfikowany przez jego x:Name. Aby uzyskać więcej informacji, zobacz x:Reference Markup Extension.

Inne x: Konstrukcje

Istnieją inne konstrukcje x: do obsługi funkcji języka XAML, ale nie są one implementowane jako rozszerzenia znaczników. Aby uzyskać więcej informacji, zobacz przestrzeń nazw XAML (x:) funkcje językowe.

Klasa bazowa MarkupExtension

Aby zdefiniować niestandardowe rozszerzenie znaczników, które może współdziałać z domyślnymi implementacjami czytników XAML i zapisów XAML w System.Xaml, należy utworzyć klasę dziedziczoną z klasy abstrakcyjnej MarkupExtension. Ta klasa ma jedną metodę zastąpienia, która jest ProvideValue. Może być również konieczne zdefiniowanie dodatkowych konstruktorów, aby obsługiwać argumenty do użycia rozszerzeń znaczników oraz pasujące właściwości możliwe do ustawienia.

Za pośrednictwem ProvideValueniestandardowe rozszerzenie znaczników ma dostęp do kontekstu usługi, który informuje o środowisku, w którym rozszerzenie znaczników jest wywoływane przez procesor XAML. W ścieżce ładowania zazwyczaj jest to XamlObjectWriter. W ścieżce zapisu jest to zazwyczaj XamlXmlWriter. Każdy raport zawiera kontekst usługi jako wewnętrzna klasa kontekstu dostawcy usług XAML, która implementuje wzorzec dostawcy usług. Aby uzyskać więcej informacji na temat dostępnych usług i co one oznaczają, zobacz Type Converters and Markup Extensions for XAML.

Klasa rozszerzenia znaczników musi używać publicznego poziomu dostępu; Procesory XAML muszą zawsze mieć możliwość utworzenia wystąpienia klasy obsługi rozszerzenia znaczników w celu korzystania z jego usług.

Definiowanie typu obsługi dla niestandardowego rozszerzenia znaczników

Podczas korzystania z usług XAML lub frameworków opartych na usługach XAML platformy .NET, masz dwie możliwości, jak nazwać typ obsługi rozszerzenia znacznika. Nazwa typu jest istotna dla sposobu, w jaki autorzy obiektów XAML próbują uzyskać dostęp i wywołać typ obsługujący rozszerzenia znaczników, gdy napotkają użycie rozszerzenia znaczników w języku XAML. Użyj jednej z następujących strategii nazewnictwa:

  • Nazwij nazwę typu, która będzie dokładnie zgodna z tokenem użycia znaczników XAML. Aby na przykład obsługiwać użycie rozszerzenia {Collate ...}, nadaj nazwę typowi obsługi Collate.
  • Nadaj nazwę typu tokenowi ciągu użycia oraz sufiksowi Extension. Aby na przykład obsługiwać użycie rozszerzenia {Collate ...}, nadaj nazwę typowi obsługi CollateExtension.

Kolejność wyszukiwania polega na wyszukaniu najpierw nazwy klasy z sufiksem Extension, a potem nazwy klasy bez sufiksu Extension.

Z perspektywy użycia znaczników, włączenie sufiksu Extension jako część użycia jest prawidłowe. Jednak zachowuje się tak, jakby Extension jest naprawdę częścią nazwy klasy, a autorzy obiektów XAML nie rozpoznają klasy obsługi rozszerzenia znaczników dla tego użycia, jeśli klasa pomocy technicznej nie ma sufiksu Extension.

Konstruktor bez parametrów

W przypadku wszystkich typów obsługi rozszerzeń znaczników należy udostępnić publiczny konstruktor bez parametrów. Konstruktor bez parametrów jest wymagany w każdym przypadku, gdy moduł zapisywania obiektów XAML tworzy wystąpienie rozszerzenia znaczników z użycia elementu obiektu. Obsługa użycia elementów obiektowych jest uzasadnionym oczekiwaniem rozszerzenia znaczników, szczególnie w kontekście serializacji. Można jednak zaimplementować rozszerzenie znaczników bez publicznego konstruktora, jeśli zamierzasz obsługiwać tylko użycie atrybutów rozszerzenia znaczników.

Jeśli zastosowanie rozszerzenia znaczników nie obejmuje argumentów, wymagany jest konstruktor bez parametrów do zapewnienia wsparcia dla tego zastosowania.

Wzorce konstruktorów i argumenty pozycyjne dla niestandardowego rozszerzenia znaczników

W przypadku rozszerzenia znaczników z zamierzonym użyciem argumentów konstruktory publiczne muszą odpowiadać trybom zamierzonego użycia. Innymi słowy, jeśli rozszerzenie znaczników ma wymagać jednego argumentu pozycyjnego jako prawidłowego użycia, należy obsługiwać publiczny konstruktor z jednym parametrem wejściowym, który przyjmuje argument pozycyjny.

Załóżmy na przykład, że rozszerzenie znaczników Collate ma obsługiwać tylko tryb, w którym istnieje jeden argument pozycyjny reprezentujący jego tryb, określony jako stała wyliczenia CollationMode. W takim przypadku powinien istnieć konstruktor z następującą formą:

public Collate(CollationMode collationMode) {...}

Na poziomie podstawowym argumenty przekazywane do rozszerzenia znaczników są ciągiem, ponieważ są przekazywane z wartości atrybutów znacznika. Możesz ustawić wszystkie ciągi argumentów i pracować z danymi wejściowymi na tym poziomie. Jednak masz dostęp do pewnego przetwarzania, które występuje przed przekazaniem argumentów rozszerzenia znaczników do klasy wspierającej.

Przetwarzanie działa koncepcyjnie tak, jakby rozszerzenie znaczników było obiektem do utworzenia, a następnie ustawiane są jego wartości składowe. Każda określona właściwość do ustawienia jest oceniana podobnie do sposobu ustawiania określonego elementu członkowskiego na utworzonym obiekcie podczas analizowania kodu XAML. Istnieją dwie ważne różnice:

  • Jak wspomniano wcześniej, typ obsługi rozszerzenia znaczników nie musi mieć konstruktora bez parametrów, aby utworzyć wystąpienie w języku XAML. Konstrukcja tego obiektu jest odroczona do momentu, gdy jego możliwe argumenty w składni tekstowej są dzielone na tokeny i oceniane jako argumenty pozycyjne lub nazwane, a odpowiedni konstruktor jest wywoływany w tym czasie.
  • Użycia rozszerzeń znaczników mogą być zagnieżdżane. Najwewnętrzniejsze rozszerzenie znaczników jest oceniane jako pierwsze. W związku z tym można założyć takie użycie i zadeklarować jeden z parametrów konstrukcyjnych jako typ, który wymaga konwertera wartości (takiego jak rozszerzenie znaczników), aby go utworzyć.

W poprzednim przykładzie pokazano zależność od takiego przetwarzania. Moduł zapisywania obiektów XAML w usługach .NET XAML przetwarza nazwy stałych wyliczeń na wartości wyliczeniowe na poziomie natywnym.

Przetwarzanie składni tekstowej parametru pozycyjnego rozszerzenia znacznikowego może również polegać na wykorzystaniu konwertera typów skojarzonego z typem, który jest obecny w argumencie konstrukcyjnym.

Argumenty są nazywane argumentami pozycyjnymi, ponieważ kolejność, w której napotkano tokeny w użyciu, odpowiada kolejności pozycyjnej parametru konstruktora, do którego są przypisane. Rozważmy na przykład następujący podpis konstruktora:

public Collate(CollationMode collationMode, object collateThis) {...}

Procesor XAML oczekuje dwóch argumentów pozycyjnych dla tego rozszerzenia znaczników. Jeśli wystąpiło użycie {Collate AlphaUp,{x:Reference circularFile}}, token AlphaUp jest wysyłany do pierwszego parametru i oceniany jako stała nazwowa wyliczeniowa CollationMode. Wynik x:Reference wewnętrznego jest wysyłany do drugiego parametru i oceniany jako obiekt.

W regułach składni i przetwarzania rozszerzeń znaczników w XAML, przecinek działa jako separator między argumentami, niezależnie od tego, czy są to argumenty pozycyjne, czy nazwane.

Duplikowanie arity argumentów pozycyjnych

Jeśli kompilator XAML napotka użycie rozszerzenia znaczników z argumentami pozycyjnymi i istnieje wiele argumentów konstruktorów, które przyjmują tę samą liczbę argumentów (zduplikowana liczba argumentów), niekoniecznie jest to błąd. Zachowanie zależy od konfigurowalnego ustawienia kontekstu schematu XAML, SupportMarkupExtensionsWithDuplicateArity. Jeśli SupportMarkupExtensionsWithDuplicateArity jest true, moduł zapisywania obiektów XAML nie powinien zgłaszać wyjątku tylko z powodów duplikowania arity. Zachowanie poza tym punktem nie jest ściśle zdefiniowane. Podstawowym założeniem projektu jest to, że kontekst schematu zawiera informacje o typie dostępne dla określonych parametrów i może podejmować próby rzutowania, które odpowiadają zduplikowanym kandydatom, aby ustalić, który podpis jest najlepszym dopasowaniem. Wyjątek może zostać zgłoszony, jeśli żadne podpisy nie mogą przejść testów nałożonych przez dany kontekst schematu działający w pisarzu obiektów XAML.

Domyślnie SupportMarkupExtensionsWithDuplicateArity jest false w XamlSchemaContext opartych na clR dla usług XAML platformy .NET. W związku z tym domyślny XamlObjectWriter zgłasza wyjątki, jeśli napotka użycie rozszerzenia znaczników, gdy w konstruktorach typu bazowego występuje zduplikowana liczba argumentów.

Argumenty nazwane dla niestandardowego rozszerzenia znaczników

Rozszerzenia znaczników określone przez XAML mogą również używać formularza nazwanych argumentów do użycia. Na pierwszym poziomie tokenizacji składnia tekstu jest podzielona na argumenty. Obecność znaku równości (=) w dowolnym argumencie identyfikuje argument jako nazwany argument. Taki argument jest również tokenizowany do pary nazwa/wartość. Nazwa w tym przypadku odnosi się do ustawialnej publicznej właściwości typu obsługi rozszerzenia znaczników. Jeśli zamierzasz obsługiwać użycie nazwanych argumentów, powinieneś zapewnić te publiczne właściwości możliwe do ustawienia. Właściwości mogą być dziedziczone, pod warunkiem, że pozostają publiczne.

Uzyskiwanie dostępu do kontekstu dostawcy usług z implementacji rozszerzenia składniowego

Dostępne usługi są takie same dla każdego konwertera wartości. Różnica polega na tym, jak każdy konwerter wartości odbiera kontekst usługi. Uzyskiwanie dostępu do usług oraz opis dostępnych usług znajdują się w temacie Type Converters and Markup Extensions for XAML.

Zastosowanie elementów właściwości w rozszerzeniu znaczników

Scenariusze użycia rozszerzeń znaczników są często projektowane z myślą o ich zastosowaniu w atrybutach. Istnieje jednak również możliwość zdefiniowania klasy pomocniczej do obsługi użycia elementu właściwości.

Aby umożliwić użycie elementów właściwości w rozszerzeniu znaczników, zdefiniuj publiczny konstruktor bez parametrów. Powinien to być konstruktor wystąpienia, który nie jest konstruktorem statycznym. Jest to wymagane, ponieważ procesor XAML musi na ogół wywoływać konstruktor bez parametrów na dowolnym elemencie obiektu, który przetwarza ze znaczników, co obejmuje klasy rozszerzeń znaczników jako elementy obiektów. W przypadku zaawansowanych scenariuszy można zdefiniować nie domyślne ścieżki konstrukcyjne dla klas. (Aby uzyskać więcej informacji, zobacz x:FactoryMethod, dyrektywa.) Nie należy jednak używać tych wzorców do celów rozszerzenia znaczników, ponieważ sprawia to, że odnajdywanie wzorca użycia jest znacznie trudniejsze zarówno dla projektantów, jak i dla użytkowników nieprzetworzonych znaczników.

Atrybutowanie dla niestandardowego rozszerzenia znaczników

Aby obsługiwać zarówno środowiska projektowe, jak i niektóre scenariusze zapisywania obiektów XAML, należy przypisać typ obsługi rozszerzenia znaczników z kilkoma atrybutami CLR. Te atrybuty wskazują na zamierzone zastosowanie rozszerzenia znaczników.

MarkupExtensionReturnTypeAttribute raportuje informacje dla Type dotyczące typu obiektu, który jest zwracany przez ProvideValue. Na podstawie swojej czystej sygnatury ProvideValue zwraca Object. Jednak różni konsumenci mogą chcieć bardziej precyzyjne informacje o typie zwracania. Obejmuje to:

  • Projektanci oraz IDE, którzy mogą zapewniać wsparcie dla rozszerzeń znaczników rozumiejących typy.
  • Zaawansowane implementacje obsługi SetMarkupExtension w klasach docelowych, które mogą polegać na wykorzystaniu refleksji do określenia typu zwracanego rozszerzenia znaczników zamiast stosowania gałęziowania na znanych implementacjach MarkupExtension według nazwy.

Serializacja użycia rozszerzeń znaczników

Gdy pisarz obiektów XAML przetwarza użycie rozszerzenia znaczników i wywołuje ProvideValue, kontekst jego wcześniejszego użycia jako rozszerzenia znaczników jest utrwalany w strumieniu węzłów XAML, ale nie w grafie obiektów. Na grafie obiektu zachowywana jest tylko wartość. Jeśli masz scenariusze projektowe lub inne powody, aby zachować oryginalne użycie rozszerzenia znaczników w serializowanym wyjściu, musisz zaprojektować własną infrastrukturę do śledzenia użycia rozszerzeń znaczników ze strumienia węzłów XAML na ścieżce ładowania. Można zaimplementować zachowanie, aby odtworzyć elementy strumienia węzła ze ścieżki ładowania i odtworzyć je dla pisarzy XAML w celu serializacji na ścieżce zapisywania, zastępując wartość w odpowiedniej pozycji strumienia węzła.

Rozszerzenia znaczników w strumieniu węzła XAML

Jeśli pracujesz z przepływem węzłów XAML na ścieżce ładowania, użycie rozszerzenia znaczników pojawia się w tym przepływie jako obiekt.

Jeśli użycie rozszerzenia znaczników używa argumentów pozycyjnych, jest reprezentowane jako obiekt początkowy z wartością inicjalizacji. Jako przybliżona reprezentacja tekstu, strumień węzłów przypomina następująco:

StartObject (XamlType jest typem definicji rozszerzenia znaczników, a nie typem zwrotnym)

StartMember (nazwa XamlMember to _InitializationText)

Value (wartość to argumenty pozycyjne jako ciąg znaków, w tym separatory)

EndMember

EndObject

Użycie rozszerzenia znaczników z nazwanymi argumentami jest reprezentowane jako obiekt z członkami o odpowiednich nazwach, z których każdy ma przypisaną wartość jako ciąg tekstowy.

Faktyczne wywoływanie implementacji rozszerzenia znaczników ProvideValue wymaga kontekstu schematu XAML, ponieważ wymaga to mapowania typów i tworzenia instancji typu obsługi rozszerzenia znaczników. Jest to jeden z powodów, dla których użycie rozszerzeń znaczników jest zachowywane w ten sposób w domyślnych strumieniach węzłów usług XAML platformy .NET — czytnik w ścieżce ładowania często nie ma dostępnego niezbędnego kontekstu schematu XAML.

Jeśli pracujesz ze strumieniem węzłów XAML na ścieżce zapisu, zazwyczaj w reprezentacji grafu obiektu nie ma niczego, co mogłoby poinformować, że obiekt do serializacji pochodził pierwotnie z użycia rozszerzeń znaczników i wyniku ProvideValue. Scenariusze wymagające zachowania użycia rozszerzeń znaczników na potrzeby round-trippingu, jednocześnie uwzględniając inne zmiany w grafie obiektów, muszą opracować własne techniki, aby zachować wiedzę o wykorzystaniu rozszerzeń znaczników pochodzących z oryginalnych danych wejściowych XAML. Na przykład aby przywrócić użycie rozszerzeń znaczników, może być konieczne pracę ze strumieniem węzła na ścieżce zapisywania, aby przywrócić użycie rozszerzeń znaczników lub wykonać jakiś typ scalania między oryginalnym kodem XAML i xAML w obie strony. Niektóre frameworki implementujące XAML, takie jak WPF, używają typów pośrednich (wyrażeń) do reprezentowania przypadków, gdzie użycia rozszerzeń znaczników dostarczyły wartości.

Zobacz też