Создание расширений разметки XAML
На программном уровне расширение разметки XAML — это класс, реализующий IMarkupExtension
или IMarkupExtension<T>
интерфейс. Исходный код стандартных расширений разметки, описанных ниже в каталоге Xamarin.Forms MarkupExtensions репозитория GitHub.
Кроме того, можно определить собственные расширения разметки XAML, производные от IMarkupExtension
или IMarkupExtension<T>
. Используйте универсальную форму, если расширение разметки получает значение определенного типа. Это касается нескольких Xamarin.Forms расширений разметки:
TypeExtension
происходит отIMarkupExtension<Type>
.ArrayExtension
происходит отIMarkupExtension<Array>
.DynamicResourceExtension
происходит отIMarkupExtension<DynamicResource>
.BindingExtension
происходит отIMarkupExtension<BindingBase>
.ConstraintExpression
происходит отIMarkupExtension<Constraint>
.
Два IMarkupExtension
интерфейса определяют только один метод с именем ProvideValue
:
public interface IMarkupExtension
{
object ProvideValue(IServiceProvider serviceProvider);
}
public interface IMarkupExtension<out T> : IMarkupExtension
{
new T ProvideValue(IServiceProvider serviceProvider);
}
Так как IMarkupExtension<T>
он является производным от IMarkupExtension
ключевого слова и включает ключевое new
слово в ProvideValue
, он содержит оба ProvideValue
метода.
Очень часто расширения разметки XAML определяют свойства, которые вносят вклад в возвращаемое значение. (Очевидное исключение — это NullExtension
, в котором ProvideValue
просто возвращается null
.) Метод ProvideValue
имеет один аргумент типа IServiceProvider
, который будет обсуждаться далее в этой статье.
Расширение разметки для указания цвета
Следующее расширение разметки XAML позволяет создавать Color
значение с помощью компонентов оттенка, насыщенности и яркости. Он определяет четыре свойства для четырех компонентов цвета, включая альфа-компонент, инициализированный до 1. Класс является производным от IMarkupExtension<Color>
указания возвращаемого 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);
}
}
Так как IMarkupExtension<T>
производный от IMarkupExtension
класса должен содержаться два ProvideValue
метода, одно Color
возвращает и другое, которое возвращает object
, но второй метод может просто вызвать первый метод.
На странице демонстрации цвета HSL показаны различные способы, которые могут отображаться в XAML-файле, чтобы HslColorExtension
указать цвет для 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>
Обратите внимание, что при HslColorExtension
использовании XML-тега четыре свойства задаются как атрибуты, но при отображении между фигурными скобками четыре свойства разделяются запятыми без кавычки. Значения по умолчанию для H
, S
и L
равны 0, а значение A
по умолчанию равно 1, поэтому эти свойства могут быть опущены, если они задают значения по умолчанию. В последнем примере показан пример, в котором светимость составляет 0, что обычно приводит к черному цвету, но альфа-канал равен 0,5, поэтому он является полупрозрачным и отображается серым на белом фоне страницы:
Расширение разметки для доступа к растровым картам
Аргументом ProvideValue
является объект, реализующий IServiceProvider
интерфейс, который определен в пространстве имен .NET System
. Этот интерфейс содержит один член, метод с именем GetService
аргумента Type
.
В ImageResourceExtension
приведенном ниже классе показано одно возможное использование IServiceProvider
и GetService
получение IXmlLineInfoProvider
объекта, который может предоставлять сведения о строке и символах, указывающих, где обнаружена определенная ошибка. В этом случае возникает исключение, если 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
полезно, если ФАЙЛ XAML должен получить доступ к файлу изображения, хранящейся в качестве внедренного ресурса в проекте библиотеки .NET Standard. Он использует Source
свойство для вызова статического ImageSource.FromResource
метода. Для этого метода требуется полное имя ресурса, состоящее из имени сборки, имени папки и имени файла, разделенного точками. Второй аргумент метода ImageSource.FromResource
предоставляет имя сборки и требуется только для сборки выпуска в UWP. Независимо от того, следует вызывать из сборки, ImageSource.FromResource
содержащей растровое изображение, что означает, что это расширение ресурса XAML не может быть частью внешней библиотеки, если изображения также не находятся в этой библиотеке. (См. раздел Дополнительные сведения о доступе к растровым изображениям, хранящимся в виде внедренных ресурсов.
Хотя ImageResourceExtension
требуется Source
задать свойство, Source
свойство указывается в атрибуте в качестве свойства содержимого класса. Это означает, что Source=
часть выражения в фигурных скобках может быть опущена. На странице "Демонстрация ресурсов изображения" элементы извлекает два изображения с помощью имени папки и имени файла, Image
разделенного точками:
<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>
Вот работающая программа:
Поставщики услуг
С помощью аргумента IServiceProvider
ProvideValue
расширения разметки XAML могут получить доступ к полезным сведениям о XAML-файле, в котором они используются. Но для успешного IServiceProvider
использования аргумента необходимо знать, какие службы доступны в определенных контекстах. Лучший способ получить представление об этой функции заключается в изучении исходного кода существующих расширений разметки XAML в папке MarkupExtensions в Xamarin.Forms репозитории на GitHub. Помните, что некоторые типы служб являются внутренними Xamarin.Forms.
В некоторых расширениях разметки XAML эта служба может оказаться полезной:
IProvideValueTarget provideValueTarget = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
Интерфейс IProvideValueTarget
определяет два свойства и TargetObject
TargetProperty
. При получении этих сведений ImageResourceExtension
в классе является Image
BindableProperty
TargetProperty
объектом для Source
свойства . TargetObject
Image
Это свойство, в котором задано расширение разметки XAML.
Вызов GetService
с аргументом typeof(IProvideValueTarget)
фактически возвращает объект типа SimpleValueTargetProvider
, который определяется в Xamarin.Forms.Xaml.Internals
пространстве имен. При приведение возвращаемого значения GetService
этого типа также можно получить к ParentObjects
свойству, который является массивом, содержащим Image
элемент, Grid
родительский и ImageResourceDemoPage
родительский элемент Grid
.
Заключение
Расширения разметки XAML играют важную роль в XAML, расширяя возможность задавать атрибуты из различных источников. Кроме того, если существующие расширения разметки XAML не предоставляют точно необходимые компоненты, вы также можете написать собственные.