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

Rozszerzenia znaczników to technika XAML służąca do uzyskiwania wartości, która nie jest typem pierwotnym ani określonym typem XAML. W przypadku użycia atrybutów rozszerzenia znaczników używają znanej sekwencji znaków otwierającego nawiasu klamrowego { , aby wprowadzić zakres rozszerzenia znaczników i zamykający nawias klamrowy } do zakończenia. 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ż podklasy z klasy zdefiniowanej MarkupExtension 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 uzyskuje się dostęp do użycia rozszerzenia znaczników, moduł zapisywania obiektów XAML może udostępniać usługi klasie niestandardowej MarkupExtension za pośrednictwem punktu 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 XAML platformy .NET 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 x: przez prefiks w składni, jak pokazano w typowym użyciu. Implementacje usług XAML platformy .NET dla tych elementów języka XAML pochodzą z klasy bazowej MarkupExtension .

Uwaga

Prefiks x: jest używany do typowego mapowania przestrzeni nazw XAML przestrzeni nazw języka XAML w głównym elemekcie produkcji 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 x: mapowania. Możesz wybrać inny token prefiksu we własnym mapowaniu przestrzeni nazw XAML, ale w tej dokumentacji przyjęto założenie domyślnego x: mapowania jako środka 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:TypeType dostarcza obiekt 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 TargetType właściwości są konkretnym przykładem. Aby uzyskać więcej informacji, zobacz x:Type Markup Extension (Rozszerzenie znaczników x:Type).

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 można je ocenić na ten typ. 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 (Rozszerzenie x:Static Markup).

x:Null

x:Null określa null jako wartość elementu członkowskiego XAML. W zależności od projektu określonych typów lub większych koncepcji null struktury 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 (Rozszerzenie znaczników o wartości null).

x:Array

x:Array obsługuje tworzenie tablic ogólnych w składni XAML w przypadkach, gdy obsługa kolekcji zapewniana przez elementy podstawowe i modele sterowania celowo nie jest używana. Aby uzyskać więcej informacji, zobacz x:Array Markup Extension (Rozszerzenie x:Array Markup). W języku XAML 2009 są dostępne jako typy pierwotne 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, czyli rozszerzenia oryginalnego zestawu języków (2006). x:Reference reprezentuje odwołanie do innego istniejącego obiektu w grafie obiektów. Ten obiekt jest identyfikowany przez jego x:Nameobiekt . Aby uzyskać więcej informacji, zobacz x:Reference Markup Extension (Rozszerzenie x:Reference Markup).

Inne x: Konstrukcje

Istnieją inne x: konstrukcje obsługujące funkcje języka XAML, ale nie są one implementowane jako rozszerzenia znaczników. Aby uzyskać więcej informacji, zobacz Funkcje języka przestrzeni nazw XAML (x:).

Klasa bazowa MarkupExtension

Aby zdefiniować niestandardowe rozszerzenie znaczników, które może współdziałać z domyślnymi implementacjami czytników XAML i składników zapisywania XAML w pliku System.Xaml, należy utworzyć klasę z klasy abstrakcyjnej MarkupExtension . Ta klasa ma jedną metodę zastąpienia, czyli ProvideValue. Może być również konieczne zdefiniowanie dodatkowych konstruktorów, aby obsługiwać argumenty użycia rozszerzenia znaczników i pasujące właściwości tabeli settable.

Za pośrednictwem ProvideValueprogramu rozszerzenie niestandardowego znaczników ma dostęp do kontekstu usługi, który zgłasza środowisko, w którym rozszerzenie znaczników jest wywoływane przez procesor XAML. W ścieżce ładowania zazwyczaj jest XamlObjectWriterto . W ścieżce zapisywania zazwyczaj jest XamlXmlWriterto . Każdy raport kontekstu 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 ich reprezentacji, zobacz Konwertery typów i Rozszerzenia znaczników dla języka 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

W przypadku korzystania z usług XAML platformy .NET opartych na usługach XAML platformy .NET dostępne są dwie opcje nazw typu obsługi rozszerzenia znaczników. Nazwa typu jest odpowiednia dla sposobu, w jaki autorzy obiektów XAML próbują uzyskać dostęp i wywołać typ obsługi 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. Na przykład aby obsługiwać {Collate ...} użycie rozszerzenia, nadaj nazwę typowi Collatepomocy technicznej .
  • Nadaj nazwę typu tokenowi ciągu użycia oraz sufiksowi Extension. Na przykład aby obsługiwać {Collate ...} użycie rozszerzenia, nadaj nazwę typowi CollateExtensionpomocy technicznej .

Kolejność wyszukiwania polega na wyszukaniu najpierw nazwy klasy -sufiksu Extension, a następnie wyszukaniu nazwy klasy bez sufiksu Extension .

Z perspektywy użycia znaczników, w tym Extension sufiks jako część użycia jest prawidłowy. Jednak zachowuje się tak, jakby Extension był naprawdę częścią nazwy klasy, a zapisy obiektów XAML nie rozpoznałyby 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 uwidocznić 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 obiektów jest uczciwym oczekiwaniem dla rozszerzenia znaczników, szczególnie w przypadku 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 użycie rozszerzenia znaczników nie ma argumentów, konstruktor bez parametrów jest wymagany do obsługi użycia.

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 Collate rozszerzenie znaczników ma obsługiwać tylko tryb, w którym istnieje jeden argument pozycyjny reprezentujący jego tryb określony jako CollationMode stała wyliczenia. 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 określonego przetwarzania, które występuje przed przekazaniem argumentów rozszerzenia znaczników do klasy pomocy technicznej.

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. Jego konstrukcja obiektu jest odroczona do momentu, aż jego możliwe argumenty w składni tekstowej są tokenizowane i oceniane jako argumenty pozycyjne lub nazwane, a odpowiedni konstruktor jest wywoływany w tym czasie.
  • Rozszerzenia znaczników mogą być zagnieżdżone. Rozszerzenie znaczników najwewnętrznych 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) do utworzenia.

W poprzednim przykładzie pokazano zależność od takiego przetwarzania. Moduł zapisywania obiektów XAML usług .NET XAML przetwarza stałe nazwy wyliczone wartości na poziomie natywnym.

Przetwarzanie składni tekstu parametru pozycyjnego rozszerzenia znaczników może również polegać na konwerterze typów skojarzonym z typem, który znajduje się 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}}, AlphaUp token jest wysyłany do pierwszego parametru i oceniany jako CollationMode wyliczenie o nazwie stała. Wynik wewnętrzny x:Reference jest wysyłany do drugiego parametru i oceniany jako obiekt.

W języku XAML określone reguły składni i przetwarzania rozszerzeń znaczników przecinek jest ogranicznikiem między argumentami, niezależnie od tego, czy te argumenty są argumentami pozycyjnymi, czy nazwanych argumentów.

Duplikowanie arity argumentów pozycyjnych

Jeśli składnik zapisywania obiektów XAML napotka użycie rozszerzenia znaczników z argumentami pozycyjnymi i istnieje wiele argumentów konstruktorów, które przyjmują liczbę argumentów (zduplikowane arity), niekoniecznie jest to błąd. Zachowanie zależy od konfigurowalnego ustawienia kontekstu schematu XAML, SupportMarkupExtensionsWithDuplicateArity. Jeśli SupportMarkupExtensionsWithDuplicateArity parametr to true, składnik 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 próbować jawnie rzutować zgodne z zduplikowanymi kandydatami, aby zobaczyć, który podpis może być najlepszym dopasowaniem. Wyjątek może być nadal zgłaszany, jeśli żadne podpisy nie mogą przejść testy nałożone przez ten konkretny kontekst schematu uruchomiony na składnik zapisywania obiektów XAML.

Domyślnie SupportMarkupExtensionsWithDuplicateArity element znajduje się false w środowisku CLR opartym na XamlSchemaContext usługach .NET XAML. W związku z tym wartość domyślna XamlObjectWriter zgłasza wyjątki, jeśli napotka użycie rozszerzenia znaczników, w przypadku gdy w konstruktorach typu kopii zapasowej występuje duplikat arity.

Nazwane argumenty 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 nazywa publiczną właściwość settable typu obsługi rozszerzenia znaczników. Jeśli zamierzasz obsługiwać użycie nazwanych argumentów, należy podać te publiczne właściwości tabeli settable. Właściwości mogą być dziedziczone, o ile pozostają publiczne.

Uzyskiwanie dostępu do kontekstu dostawcy usług z implementacji rozszerzenia znaczników

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 i dostępnych usług opisano w temacie Type Converters and Markup Extensions for XAML (Konwertery typów i rozszerzenia znaczników dla języka XAML).

Użycie elementu właściwości rozszerzenia znaczników

Scenariusze użycia rozszerzeń znaczników są często projektowane przy użyciu rozszerzenia znaczników w użyciu atrybutów. Istnieje jednak również możliwość zdefiniowania klasy pomocniczej do obsługi użycia elementu właściwości.

Aby obsługiwać użycie elementu właściwości rozszerzenia 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 elemecie obiektu, który przetwarza z znaczników, i obejmuje to klasy rozszerzeń znaczników jako elementy obiektu. W przypadku zaawansowanych scenariuszy można zdefiniować nie domyślne ścieżki konstrukcyjne dla klas. (Aby uzyskać więcej informacji, zobacz x:FactoryMethod Directive). 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.

Przypisywanie 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 zgłaszają zamierzone użycie rozszerzenia znaczników.

MarkupExtensionReturnTypeAttributeType raportuje informacje o typie obiektu, który ProvideValue zwraca. Po jego czystym podpisie ProvideValue zwraca wartość Object. Jednak różni konsumenci mogą chcieć bardziej precyzyjne informacje o typie zwracania. Obejmuje on:

  • Projektant i środowisk IDE, którzy mogą mieć możliwość zapewnienia obsługi rozszerzeń znaczników obsługujących typy.
  • Zaawansowane implementacje SetMarkupExtension procedur obsługi w klasach docelowych, które mogą polegać na odbiciu w celu określenia typu zwracanego rozszerzenia znaczników zamiast rozgałęziania na określonych znanych MarkupExtension implementacjach według nazwy.

Serializacja użycia rozszerzeń znaczników

Gdy moduł zapisywania obiektów XAML przetwarza użycie rozszerzenia znaczników i wywołuje ProvideValueelement , kontekst dla niego, który wcześniej był użyciem rozszerzenia znaczników, utrzymuje się w strumieniu węzła XAML, ale nie w grafie obiektu. Na grafie obiektu zachowywana jest tylko wartość. Jeśli masz scenariusze projektowe lub inne przyczyny utrwalania oryginalnego użycia rozszerzenia znaczników do serializacji danych wyjściowych, musisz zaprojektować własną infrastrukturę do śledzenia użycia rozszerzeń znaczników ze strumienia węzła XAML ścieżki obciążenia. Można zaimplementować zachowanie, aby odtworzyć elementy strumienia węzła ze ścieżki ładowania i odtworzyć je z powrotem do składników zapisywania XAML w celu serializacji w ścieżce zapisywania, podstawiając wartość w odpowiedniej pozycji strumienia węzła.

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

Jeśli pracujesz ze strumieniem węzła XAML na ścieżce ładowania, w strumieniu węzła jako obiekt pojawi się użycie rozszerzenia znaczników.

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

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

StartMember (nazwa obiektu to XamlMember_InitializationText)

Value (wartość to argumenty pozycyjne jako ciąg, w tym interweniujące ograniczniki)

EndMember

EndObject

Użycie rozszerzenia znaczników z nazwanymi argumentami jest reprezentowane jako obiekt z elementami członkowskimi odpowiednich nazw, każdy zestaw z wartościami ciągu tekstowego.

W rzeczywistości wywoływanie ProvideValue implementacji rozszerzenia znaczników wymaga kontekstu schematu XAML, ponieważ wymaga to mapowania typów i tworzenia wystąpienia 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 — część czytelnika ścieżki ładowania często nie ma dostępnego niezbędnego kontekstu schematu XAML.

Jeśli pracujesz ze strumieniem węzła XAML na ścieżce zapisywania, zazwyczaj w reprezentacji grafu obiektu nie ma nic, co może poinformować, że obiekt do serializacji został pierwotnie dostarczony przez użycie rozszerzenia znaczników i ProvideValue wynik. Scenariusze, które wymagają utrwalania użycia rozszerzeń znaczników na potrzeby zaokrąglania, a także przechwytywania innych zmian w grafie obiektów, muszą opracować własne techniki zachowania wiedzy na temat użycia rozszerzenia znaczników na podstawie 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 struktury implementowania XAML, takie jak WPF, używają typów pośrednich (wyrażeń), aby pomóc w reprezentowaniu przypadków, w których użycie rozszerzeń znaczników dostarczyło wartości.

Zobacz też