Klasy XAML i niestandardowe dla WPF

Język XAML zaimplementowany w strukturach środowiska uruchomieniowego języka wspólnego (CLR) obsługuje możliwość definiowania niestandardowej klasy lub struktury w dowolnym języku środowiska uruchomieniowego języka wspólnego (CLR), a następnie uzyskiwanie dostępu do tej klasy przy użyciu znaczników XAML. Można użyć kombinacji typów zdefiniowanych w programie Windows Presentation Foundation (WPF) i typów niestandardowych w ramach tego samego pliku znaczników, zazwyczaj mapując typy niestandardowe na prefiks przestrzeni nazw XAML. W tym temacie omówiono wymagania, które klasa niestandardowa musi spełniać, aby można było jej używać jako elementu XAML.

Klasy niestandardowe w aplikacjach lub zestawach

Klasy niestandardowe, które są używane w języku XAML, można zdefiniować na dwa różne sposoby: w obrębie kodu lub innego kodu tworzącego podstawową aplikację Windows Presentation Foundation (WPF) lub jako klasę w osobnym zestawie, takim jak plik wykonywalny lub biblioteka DLL używana jako biblioteka klas. Każde z tych podejść ma szczególne zalety i wady.

  • Zaletą tworzenia biblioteki klas jest to, że wszystkie takie klasy niestandardowe mogą być współużytkowane w wielu różnych możliwych aplikacjach. Oddzielna biblioteka ułatwia również kontrolowanie problemów z przechowywaniem wersji aplikacji i upraszcza tworzenie klasy, w której zamierzone użycie klasy jest elementem głównym na stronie XAML.

  • Zaletą definiowania klas niestandardowych w aplikacji jest to, że ta technika jest stosunkowo uproszczona i minimalizuje problemy z wdrażaniem i testowaniem napotkanym podczas wprowadzania oddzielnych zestawów poza główny plik wykonywalny aplikacji.

  • Niezależnie od tego, czy zdefiniowano w tym samym lub innym zestawie, klasy niestandardowe muszą być mapowane między przestrzenią nazw CLR i przestrzenią nazw XML, aby można było ich używać w języku XAML jako elementami. Zobacz Przestrzenie nazw XAML i mapowanie przestrzeni nazw dla języka WPF XAML.

Wymagania dotyczące niestandardowej klasy jako elementu XAML

Aby można było utworzyć wystąpienie elementu obiektu, klasa musi spełniać następujące wymagania:

  • Klasa niestandardowa musi być publiczna i obsługiwać domyślny (bez parametrów) publiczny konstruktor. (Zobacz następującą sekcję, aby uzyskać uwagi dotyczące struktur).

  • Klasa niestandardowa nie może być klasą zagnieżdżonych. Zagnieżdżone klasy i "kropka" w ich ogólnej składni użycia CLR zakłócają inne funkcje WPF i/lub XAML, takie jak dołączone właściwości.

Oprócz włączania składni elementu obiektu definicja obiektu umożliwia również składnię elementu właściwości dla innych właściwości publicznych, które przyjmują ten obiekt jako typ wartości. Jest to spowodowane tym, że obiekt można teraz utworzyć wystąpienie jako element obiektu i może wypełnić wartość elementu właściwości takiej właściwości.

Struktury

Struktury definiowane jako typy niestandardowe są zawsze w stanie tworzyć w języku XAML w WPF . Dzieje się tak, ponieważ kompilatory CLR niejawnie tworzą konstruktor bez parametrów dla struktury, która inicjuje wszystkie wartości właściwości do ich wartości domyślnych. W niektórych przypadkach domyślne zachowanie konstrukcji i/lub użycie elementu obiektu dla struktury nie jest pożądane. Może to być spowodowane tym, że struktura ma wypełniać wartości i funkcjonować koncepcyjnie jako związek, gdzie zawarte wartości mogą mieć wzajemnie wykluczające się interpretacje, a tym samym żadna z jego właściwości nie jest ustawiana. Przykładem takiej struktury jest GridLengthWPF . Ogólnie rzecz biorąc, takie struktury powinny implementować konwerter typów, tak aby wartości mogły być wyrażone w postaci atrybutu, przy użyciu konwencji ciągów, które tworzą różne interpretacje lub tryby wartości struktury. Struktura powinna również uwidaczniać podobne zachowanie w przypadku konstruowania kodu za pomocą konstruktora bez parametrów.

Wymagania dotyczące właściwości klasy niestandardowej jako atrybutów XAML

Właściwości muszą odwoływać się do typu by-value (takiego jak typ pierwotny) lub użyć klasy dla typu, który ma konstruktor bez parametrów lub dedykowany konwerter typów, do którego może uzyskać dostęp procesor XAML. W implementacji XAML CLR procesory XAML znajdują takie konwertery za pomocą natywnej obsługi języków pierwotnych lub za pomocą zastosowania TypeConverterAttribute do typu lub elementu członkowskiego w definicjach typów zapasowych

Alternatywnie właściwość może odwoływać się do abstrakcyjnego typu klasy lub interfejsu. W przypadku klas abstrakcyjnych lub interfejsów oczekiwanie na analizowanie kodu XAML polega na tym, że wartość właściwości musi być wypełniona praktycznymi wystąpieniami klas, które implementują interfejs, lub wystąpienia typów, które pochodzą z klasy abstrakcyjnej.

Właściwości można zadeklarować w klasie abstrakcyjnej, ale można ustawić tylko na klasach praktycznych, które pochodzą z klasy abstrakcyjnej. Jest to spowodowane tym, że utworzenie elementu obiektu dla klasy w ogóle wymaga publicznego konstruktora bez parametrów w klasie.

TypeConverter Enabled Attribute Syntax

Jeśli podasz dedykowany, przypisany konwerter typów na poziomie klasy, zastosowana konwersja typów umożliwia składnię atrybutów dla każdej właściwości, która musi utworzyć wystąpienie tego typu. Konwerter typów nie włącza użycia elementu obiektu typu; tylko obecność konstruktora bez parametrów dla tego typu umożliwia użycie elementu obiektu. W związku z tym właściwości, które są włączone konwerter typów, zazwyczaj nie są używane w składni właściwości, chyba że sam typ obsługuje również składnię elementu obiektu. Wyjątkiem jest to, że można określić składnię elementu właściwości, ale element właściwości zawiera ciąg. To użycie jest naprawdę zasadniczo równoważne użyciu składni atrybutów, a takie użycie nie jest powszechne, chyba że istnieje potrzeba bardziej niezawodnej obsługi białych znaków wartości atrybutu. Na przykład poniżej przedstawiono użycie elementu właściwości, który przyjmuje ciąg, a odpowiednik użycia atrybutu:

<Button>Hallo!
  <Button.Language>
    de-DE
  </Button.Language>
</Button>
<Button Language="de-DE">Hallo!</Button>

Przykłady właściwości, w których składnia atrybutu jest dozwolona, ale składnia elementu właściwości, która zawiera element obiektu, jest niedozwolona za pośrednictwem języka XAML, to różne właściwości, które przyjmują Cursor typ. Klasa Cursor ma dedykowany konwerter CursorConvertertypów, ale nie uwidacznia konstruktora bez parametrów, więc Cursor właściwość można ustawić tylko za pomocą składni atrybutu, mimo że rzeczywisty Cursor typ jest typem odwołania.

Konwertery typów właściwości

Alternatywnie sama właściwość może zadeklarować konwerter typów na poziomie właściwości. Umożliwia to utworzenie wystąpienia obiektów typu właściwości w tekście przez przetwarzanie przychodzących wartości ciągów atrybutu jako danych wejściowych dla ConvertFrom operacji na podstawie odpowiedniego typu. Zazwyczaj odbywa się to w celu zapewnienia wygody dostępu, a nie jako jedynego sposobu włączania ustawiania właściwości w języku XAML. Można jednak również użyć konwerterów typów dla atrybutów, w których chcesz użyć istniejących typów CLR, które nie dostarczają konstruktora bez parametrów lub konwertera typów atrybutów. Przykłady z interfejsu API WPF to pewne właściwości, które przyjmują CultureInfo typ. W takim przypadku WPF użył istniejącego typu programu Microsoft .NET Framework CultureInfo w celu lepszego rozwiązania problemów ze zgodnością i scenariuszami migracji, które były używane we wcześniejszych wersjach platform, ale CultureInfo typ nie obsługiwał niezbędnych konstruktorów ani konwersji typu na poziomie typu, aby można było używać ich bezpośrednio jako wartości właściwości XAML.

Zawsze, gdy uwidaczniasz właściwość, która ma użycie języka XAML, szczególnie jeśli jesteś autorem kontrolek, zdecydowanie należy rozważyć utworzenie kopii zapasowej tej właściwości z właściwością zależności. Jest to szczególnie istotne w przypadku korzystania z istniejącej implementacji procesora XAML (Windows Presentation Foundation, WPF), ponieważ można zwiększyć wydajność przy użyciu DependencyProperty kopii zapasowej. Właściwość zależności uwidacznia funkcje systemu właściwości dla właściwości, których użytkownicy będą oczekiwać dla właściwości dostępnej w języku XAML. Obejmuje to funkcje, takie jak animacja, powiązanie danych i obsługa stylu. Aby uzyskać więcej informacji, zobacz Właściwości zależności niestandardowych i Właściwości ładowania i zależności XAML.

Pisanie i przypisywanie konwertera typów

Czasami trzeba będzie napisać niestandardową TypeConverter klasę pochodną, aby zapewnić konwersję typu dla typu właściwości. Aby uzyskać instrukcje dotyczące sposobu uzyskiwania i tworzenia konwertera typów, który może obsługiwać użycie języka XAML oraz jak zastosować metodę TypeConverterAttribute, zobacz TypeConverters i XAML.

Wymagania dotyczące składni atrybutu programu obsługi zdarzeń XAML dla zdarzeń klasy niestandardowej

Aby można było używać go jako zdarzenia CLR, zdarzenie musi być uwidocznione jako zdarzenie publiczne w klasie obsługującej konstruktor bez parametrów lub w klasie abstrakcyjnej, do której można uzyskać dostęp do zdarzenia w klasach pochodnych. Aby można było używać wygodnie jako zdarzenia kierowanego, zdarzenie CLR powinno implementować jawne add i remove metody, które dodają i usuwają programy obsługi dla sygnatury zdarzeń CLR i przekazują te procedury obsługi do AddHandler metod i RemoveHandler . Te metody dodają lub usuwają programy obsługi do magazynu obsługi zdarzeń kierowanych w wystąpieniu, do którego jest dołączone zdarzenie.

Uwaga

Istnieje możliwość zarejestrowania programów obsługi bezpośrednio dla zdarzeń kierowanych przy użyciu metody AddHandleri celowo nie zdefiniowanie zdarzenia CLR, które uwidacznia kierowane zdarzenie. Nie jest to zwykle zalecane, ponieważ zdarzenie nie włączy składni atrybutów XAML do dołączania programów obsługi, a wynikowa klasa będzie oferować mniej przezroczysty widok XAML możliwości tego typu.

Pisanie właściwości kolekcji

Właściwości, które przyjmują typ kolekcji, mają składnię XAML, która umożliwia określenie obiektów dodawanych do kolekcji. Ta składnia ma dwie istotne funkcje.

  • Obiekt, który jest obiektem kolekcji, nie musi być określony w składni elementu obiektu. Obecność tego typu kolekcji jest niejawna za każdym razem, gdy określisz właściwość w języku XAML, która przyjmuje typ kolekcji.

  • Elementy podrzędne właściwości kolekcji w adiustacji są przetwarzane, aby stać się elementami członkowskimi kolekcji. Zazwyczaj dostęp kodu do elementów członkowskich kolekcji jest wykonywany za pośrednictwem metod list/słowników, takich jak Add, lub za pośrednictwem indeksatora. Jednak składnia XAML nie obsługuje metod ani indeksatorów (wyjątek: XAML 2009 może obsługiwać metody, ale użycie języka XAML 2009 ogranicza możliwe użycie WPF; zobacz Funkcje języka XAML 2009). Kolekcje są oczywiście bardzo typowym wymaganiem do tworzenia drzewa elementów i potrzebujesz jakiegoś sposobu na wypełnienie tych kolekcji w deklaratywnym języku XAML. W związku z tym elementy podrzędne właściwości kolekcji są przetwarzane przez dodanie ich do kolekcji, która jest wartością typu właściwości kolekcji.

Implementacja usług XAML programu .NET Framework, a tym samym procesor WPF XAML używa następującej definicji dla właściwości kolekcji. Typ właściwości musi implementować jedną z następujących właściwości:

Każdy z tych typów w clR ma metodę Add , która jest używana przez procesor XAML do dodawania elementów do bazowej kolekcji podczas tworzenia grafu obiektów.

Uwaga

Typy ogólne List i Dictionary interfejsy (IList<T> i IDictionary<TKey,TValue>) nie są obsługiwane do wykrywania kolekcji przez procesor XAML WPF. Można jednak użyć List<T> klasy jako klasy bazowej, ponieważ implementuje ją bezpośrednio lub Dictionary<TKey,TValue> jako klasę bazową, ponieważ implementuje IListIDictionary ją bezpośrednio.

Podczas deklarowania właściwości, która przyjmuje kolekcję, należy zachować ostrożność co do sposobu inicjowania tej wartości właściwości w nowych wystąpieniach typu. Jeśli nie implementujesz właściwości jako właściwości zależności, właściwość użyj pola zapasowego, które wywołuje konstruktor typu kolekcji, jest odpowiedni. Jeśli właściwość jest właściwością zależności, może być konieczne zainicjowanie właściwości kolekcji w ramach domyślnego konstruktora typu. Jest to spowodowane tym, że właściwość zależności przyjmuje jej wartość domyślną z metadanych i zazwyczaj nie chcesz, aby początkowa wartość właściwości kolekcji był statyczną, udostępnioną kolekcją. Każde wystąpienie kolekcji powinno zawierać wystąpienie typu. Aby uzyskać więcej informacji, zobacz Właściwości zależności niestandardowych.

Możesz zaimplementować niestandardowy typ kolekcji dla właściwości kolekcji. Ze względu na niejawne traktowanie właściwości kolekcji niestandardowy typ kolekcji nie musi dostarczać konstruktora bez parametrów w celu niejawnego użycia w języku XAML. Można jednak opcjonalnie podać konstruktor bez parametrów dla typu kolekcji. Może to być opłacalne rozwiązanie. Jeśli nie podasz konstruktora bez parametrów, nie można jawnie zadeklarować kolekcji jako elementu obiektu. Niektórzy autorzy znaczników mogą preferować wyświetlanie jawnej kolekcji w ramach stylu znaczników. Ponadto konstruktor bez parametrów może uprościć wymagania inicjowania podczas tworzenia nowych obiektów, które używają typu kolekcji jako wartości właściwości.

Deklarowanie właściwości zawartości XAML

Język XAML definiuje koncepcję właściwości zawartości XAML. Każda klasa, która może być używana w składni obiektu, może mieć dokładnie jedną właściwość zawartości XAML. Aby zadeklarować właściwość jako właściwość zawartości XAML dla klasy, zastosuj element ContentPropertyAttribute jako część definicji klasy. Określ nazwę zamierzonej właściwości zawartości XAML jako Name w atrybucie . Właściwość jest określana jako ciąg według nazwy, a nie jako konstrukcja odbicia, taka jak PropertyInfo.

Właściwość kolekcji można określić jako właściwość zawartości XAML. Powoduje to użycie tej właściwości, w której element obiektu może mieć co najmniej jeden element podrzędny bez żadnych interweniujących elementów obiektu kolekcji lub tagów elementów właściwości. Te elementy są następnie traktowane jako wartość właściwości zawartości XAML i dodawane do wystąpienia kolekcji zapasowej.

Niektóre istniejące właściwości zawartości XAML używają typu Objectwłaściwości . Umożliwia to właściwość zawartości XAML, która może przyjmować wartości pierwotne, takie jak , String a także przyjmuje pojedynczą wartość obiektu odwołania. Jeśli korzystasz z tego modelu, typ jest odpowiedzialny za określanie typu, a także obsługę możliwych typów. Typową przyczyną Object typu zawartości jest obsługa zarówno prostego sposobu dodawania zawartości obiektu jako ciągu (który otrzymuje domyślne traktowanie prezentacji) lub zaawansowanego sposobu dodawania zawartości obiektu, która określa prezentację inną niż domyślną lub dodatkowe dane.

Serializowanie kodu XAML

W przypadku niektórych scenariuszy, takich jak jeśli jesteś autorem kontrolek, możesz również upewnić się, że każda reprezentacja obiektu, którą można utworzyć w języku XAML, może być również serializowana z powrotem do równoważnego znaczników XAML. Wymagania dotyczące serializacji nie zostały opisane w tym temacie. Zobacz Omówienie tworzenia kontrolek oraz drzewo elementów i serializacja.

Zobacz też