Tworzenie rozszerzeń struktury znaczników XAML
Na poziomie programowym rozszerzenie znaczników XAML to klasa, która implementuje IMarkupExtension
interfejs lub IMarkupExtension<T>
. Kod źródłowy standardowych rozszerzeń znaczników opisanych poniżej można eksplorować w katalogu Xamarin.Forms MarkupExtensions repozytorium GitHub.
Istnieje również możliwość zdefiniowania własnych niestandardowych rozszerzeń znaczników XAML przez wyprowadzenie z lub IMarkupExtension
IMarkupExtension<T>
. Użyj formularza ogólnego, jeśli rozszerzenie znaczników uzyskuje wartość określonego typu. Jest to przypadek z kilkoma Xamarin.Forms rozszerzeniami znaczników:
TypeExtension
pochodzi zIMarkupExtension<Type>
ArrayExtension
pochodzi zIMarkupExtension<Array>
DynamicResourceExtension
pochodzi zIMarkupExtension<DynamicResource>
BindingExtension
pochodzi zIMarkupExtension<BindingBase>
ConstraintExpression
pochodzi zIMarkupExtension<Constraint>
IMarkupExtension
Dwa interfejsy definiują tylko jedną metodę o nazwie ProvideValue
:
public interface IMarkupExtension
{
object ProvideValue(IServiceProvider serviceProvider);
}
public interface IMarkupExtension<out T> : IMarkupExtension
{
new T ProvideValue(IServiceProvider serviceProvider);
}
Ponieważ IMarkupExtension<T>
pochodzi z IMarkupExtension
i zawiera new
słowo kluczowe w , ProvideValue
zawiera obie ProvideValue
metody.
Bardzo często rozszerzenia znaczników XAML definiują właściwości, które przyczyniają się do zwracanej wartości. (Oczywistym wyjątkiem jest NullExtension
, w którym ProvideValue
po prostu zwraca wartość null
. Metoda ProvideValue
ma jeden argument typu IServiceProvider
, który zostanie omówiony w dalszej części tego artykułu.
Rozszerzenie znaczników do określania koloru
Następujące rozszerzenie znaczników XAML umożliwia konstruowanie Color
wartości przy użyciu składników odcieni, nasycenia i jasności. Definiuje cztery właściwości dla czterech składników koloru, w tym składnik alfa zainicjowany do 1. Klasa pochodzi z IMarkupExtension<Color>
, aby wskazać wartość zwracaną Color
:
public class HslColorExtension : IMarkupExtension<Color>
{
public double H { set; get; }
public double S { set; get; }
public double L { set; get; }
public double A { set; get; } = 1.0;
public Color ProvideValue(IServiceProvider serviceProvider)
{
return Color.FromHsla(H, S, L, A);
}
object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider)
{
return (this as IMarkupExtension<Color>).ProvideValue(serviceProvider);
}
}
Ponieważ IMarkupExtension<T>
pochodzi z IMarkupExtension
klasy , klasa musi zawierać dwie ProvideValue
metody, jeden, który zwraca i drugi, który zwraca Color
object
wartość , ale druga metoda może po prostu wywołać pierwszą metodę.
Strona pokazu koloru HSL przedstawia różne sposoby wyświetlania HslColorExtension
w pliku XAML w celu określenia koloru elementu BoxView
:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MarkupExtensions"
x:Class="MarkupExtensions.HslColorDemoPage"
Title="HSL Color Demo">
<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="BoxView">
<Setter Property="WidthRequest" Value="80" />
<Setter Property="HeightRequest" Value="80" />
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="VerticalOptions" Value="CenterAndExpand" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout>
<BoxView>
<BoxView.Color>
<local:HslColorExtension H="0" S="1" L="0.5" A="1" />
</BoxView.Color>
</BoxView>
<BoxView>
<BoxView.Color>
<local:HslColor H="0.33" S="1" L="0.5" />
</BoxView.Color>
</BoxView>
<BoxView Color="{local:HslColorExtension H=0.67, S=1, L=0.5}" />
<BoxView Color="{local:HslColor H=0, S=0, L=0.5}" />
<BoxView Color="{local:HslColor A=0.5}" />
</StackLayout>
</ContentPage>
Zwróć uwagę, że jeśli HslColorExtension
jest tagiem XML, cztery właściwości są ustawiane jako atrybuty, ale gdy pojawia się między nawiasami klamrowymi, cztery właściwości są oddzielone przecinkami bez znaków cudzysłowu. Wartości domyślne dla H
wartości , S
i L
to 0, a wartość A
domyślna to 1, więc te właściwości można pominąć, jeśli chcesz, aby zostały ustawione na wartości domyślne. W ostatnim przykładzie pokazano przykład, w którym jasność wynosi 0, co zwykle powoduje kolor, ale kanał alfa wynosi 0,5, więc jest pół przezroczysty i jest szary na białym tle strony:
Rozszerzenie znaczników na potrzeby uzyskiwania dostępu do map bitowych
Argument ProvideValue
to obiekt, który implementuje IServiceProvider
interfejs zdefiniowany w przestrzeni nazw platformy .NET System
. Ten interfejs ma jeden element członkowski, metodę o nazwie GetService
z argumentem Type
.
W ImageResourceExtension
poniższej IServiceProvider
klasie przedstawiono jedno możliwe użycie obiektu i GetService
uzyskanie IXmlLineInfoProvider
obiektu, który może dostarczyć informacje o wierszach i znakach wskazujące miejsce wykrycia określonego błędu. W takim przypadku zgłaszany jest wyjątek, gdy właściwość nie została ustawiona Source
:
[ContentProperty("Source")]
class ImageResourceExtension : IMarkupExtension<ImageSource>
{
public string Source { set; get; }
public ImageSource ProvideValue(IServiceProvider serviceProvider)
{
if (String.IsNullOrEmpty(Source))
{
IXmlLineInfoProvider lineInfoProvider = serviceProvider.GetService(typeof(IXmlLineInfoProvider)) as IXmlLineInfoProvider;
IXmlLineInfo lineInfo = (lineInfoProvider != null) ? lineInfoProvider.XmlLineInfo : new XmlLineInfo();
throw new XamlParseException("ImageResourceExtension requires Source property to be set", lineInfo);
}
string assemblyName = GetType().GetTypeInfo().Assembly.GetName().Name;
return ImageSource.FromResource(assemblyName + "." + Source, typeof(ImageResourceExtension).GetTypeInfo().Assembly);
}
object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider)
{
return (this as IMarkupExtension<ImageSource>).ProvideValue(serviceProvider);
}
}
ImageResourceExtension
Jest pomocny, gdy plik XAML musi uzyskać dostęp do pliku obrazu przechowywanego jako zasób osadzony w projekcie biblioteki .NET Standard. Używa Source
właściwości do wywoływania metody statycznej ImageSource.FromResource
. Ta metoda wymaga w pełni kwalifikowanej nazwy zasobu, która składa się z nazwy zestawu, nazwy folderu i nazwy pliku oddzielonego kropkami. Drugi argument metody ImageSource.FromResource
zawiera nazwę zestawu i jest wymagany tylko dla kompilacji wydania na platformie UWP. Niezależnie od tego, należy wywołać z zestawu zawierającego mapę bitową, co oznacza, ImageSource.FromResource
że to rozszerzenie zasobu XAML nie może być częścią biblioteki zewnętrznej, chyba że obrazy znajdują się również w tej bibliotece. (Zobacz Artykuł Embedded Images (Obrazy osadzone) zawiera więcej informacji na temat uzyskiwania dostępu do map bitowych przechowywanych jako zasoby osadzone).
Mimo że ImageResourceExtension
właściwość wymaga ustawienia właściwości, Source
właściwość jest wskazywana w atrybucie Source
jako właściwość content klasy. Oznacza to, że Source=
część wyrażenia w nawiasach klamrowych może zostać pominięta. Na stronie Image
Pokaz zasobu obrazu elementy pobierają dwa obrazy przy użyciu nazwy folderu i nazwy pliku rozdzielone kropkami:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MarkupExtensions"
x:Class="MarkupExtensions.ImageResourceDemoPage"
Title="Image Resource Demo">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Image Source="{local:ImageResource Images.SeatedMonkey.jpg}"
Grid.Row="0" />
<Image Source="{local:ImageResource Images.FacePalm.jpg}"
Grid.Row="1" />
</Grid>
</ContentPage>
Oto uruchomiony program:
Dostawcy usług
Używając argumentu IServiceProvider
do ProvideValue
, rozszerzenia znaczników XAML mogą uzyskać dostęp do przydatnych informacji o pliku XAML, w którym są używane. Jednak aby pomyślnie użyć argumentu IServiceProvider
, musisz wiedzieć, jakiego rodzaju usługi są dostępne w określonych kontekstach. Najlepszym sposobem poznania tej funkcji jest zbadanie kodu źródłowego istniejących rozszerzeń znaczników XAML w folderze MarkupExtensions w repozytorium w Xamarin.Forms usłudze GitHub. Należy pamiętać, że niektóre typy usług są wewnętrzne w usłudze Xamarin.Forms.
W niektórych rozszerzeniach znaczników XAML ta usługa może być przydatna:
IProvideValueTarget provideValueTarget = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
Interfejs IProvideValueTarget
definiuje dwie właściwości i TargetObject
TargetProperty
. Gdy te informacje są uzyskiwane w ImageResourceExtension
klasie, TargetObject
jest Image
elementem i TargetProperty
jest obiektem BindableProperty
właściwości Source
Image
. Jest to właściwość, na której ustawiono rozszerzenie znaczników XAML.
Wywołanie GetService
z argumentem typeof(IProvideValueTarget)
faktycznie zwraca obiekt typu SimpleValueTargetProvider
, który jest zdefiniowany w Xamarin.Forms.Xaml.Internals
przestrzeni nazw. Jeśli rzutujesz wartość zwracaną GetService
dla tego typu, możesz również uzyskać dostęp do właściwości, która jest tablicą ParentObjects
zawierającą Image
element, Grid
element nadrzędny i ImageResourceDemoPage
element nadrzędny obiektu Grid
.
Podsumowanie
Rozszerzenia znaczników XAML odgrywają istotną rolę w języku XAML, rozszerzając możliwość ustawiania atrybutów z różnych źródeł. Ponadto jeśli istniejące rozszerzenia znaczników XAML nie udostępniają dokładnie potrzebnych elementów, możesz również napisać własne.