Создание расширений разметки XAML
На уровне разработчика расширение разметки XAML для многоплатформенного интерфейса приложения .NET (.NET MAUI) — это класс, реализующий IMarkupExtension интерфейс или IMarkupExtension<T> интерфейс. Кроме того, можно определить собственные расширения разметки XAML, производные от IMarkupExtension или IMarkupExtension<T>. Используйте универсальную форму, если расширение разметки получает значение определенного типа. Это относится к нескольким расширениям разметки MAUI .NET:
TypeExtension
происходит отIMarkupExtension<Type>
.ArrayExtension
происходит отIMarkupExtension<Array>
.DynamicResourceExtension
происходит отIMarkupExtension<DynamicResource>
.BindingExtension
происходит отIMarkupExtension<BindingBase>
.
Все классы, реализующие IMarkupExtension или IMarkupExtension<T> которые должны быть аннотированы с помощью RequireServiceAttribute или AcceptEmptyServiceProviderAttribute. Дополнительные сведения см. в разделе "Поставщики услуг".
Два 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 определяют свойства, которые вносят вклад в возвращаемое значение, и ProvideValue
метод имеет один аргумент типа IServiceProvider
. Дополнительные сведения о поставщиках услуг см. в разделе "Поставщики услуг".
Создание расширения разметки
В следующем расширении разметки XAML показано, как создать собственное расширение разметки. Он позволяет создавать Color значение с помощью компонентов оттенка, насыщенности и светимости. Он определяет четыре свойства для четырех компонентов цвета, включая альфа-компонент, инициализированный до 1. Класс является производным от IMarkupExtension<Color>
указания возвращаемого Color значения:
public class HslColorExtension : IMarkupExtension<Color>
{
public float H { get; set; }
public float S { get; set; }
public float L { get; set; }
public float A { get; set; } = 1.0f;
public Color ProvideValue(IServiceProvider serviceProvider)
{
return Color.FromHsla(H, S, L, A);
}
object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider)
{
return (this as IMarkupExtension<Color>).ProvideValue(serviceProvider);
}
}
[AcceptEmptyServiceProvider]
public class HslColorExtension : IMarkupExtension<Color>
{
public float H { get; set; }
public float S { get; set; }
public float L { get; set; }
public float A { get; set; } = 1.0f;
public Color ProvideValue(IServiceProvider serviceProvider)
{
return Color.FromHsla(H, S, L, A);
}
object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider)
{
return (this as IMarkupExtension<Color>).ProvideValue(serviceProvider);
}
}
Это расширение разметки аннотировано, AcceptEmptyServiceProviderAttribute так как оно не использует службу от поставщика услуг. Дополнительные сведения см. в разделе "Поставщики услуг".
Поскольку IMarkupExtension<T> наследуется от IMarkupExtensionкласса, класс должен содержать два ProvideValue
метода, один возвращает и другой, который возвращает Color , object
но второй метод может вызывать первый метод.
Использование расширения разметки
Следующий код XAML демонстрирует различные подходы, которые можно использовать для вызова HslColorExtension
цвета для указания цвета:BoxView
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MarkupExtensions"
x:Class="MarkupExtensions.HslColorDemoPage"
Title="HSL Color Demo">
<ContentPage.Resources>
<Style TargetType="BoxView">
<Setter Property="WidthRequest" Value="80" />
<Setter Property="HeightRequest" Value="80" />
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="VerticalOptions" Value="Center" />
</Style>
</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, поэтому он является полупрозрачным и отображается серым на белом фоне страницы:
Поставщики услуг
С помощью аргумента IServiceProvider
ProvideValue
расширения разметки XAML могут получить доступ к данным о XAML-файле, в котором они используются. Например, служба позволяет получить данные об объекте, IProvideValueTarget
к которого применяется расширение разметки:
IProvideValueTarget provideValueTarget = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
Интерфейс IProvideValueTarget
определяет два свойства и TargetObject
TargetProperty
. Если эти сведения получены в HslColorExtension
классе, TargetObject
это BoxView свойство и TargetProperty
свойство Color
BoxView. Это свойство, в котором задано расширение разметки XAML.
Все классы, реализующие IMarkupExtension или IMarkupExtension<T> которые должны быть аннотированы либо с помощью RequireServiceAttribute AcceptEmptyServiceProviderAttribute:
Для каждого использования
serviceProvider.GetService(typeof(T))
в методеProvideValue
класс должен быть помечен следующим[RequireService(typeof(T))]
образом:[RequireService([typeof(IReferenceProvider), typeof(IProvideValueTarget)])] public class MyMarkupExtension : IMarkupExtension { public object ProvideValue(IServiceProvider serviceProvider) { ... var referenceProvider = serviceProvider.GetService<IReferenceProvider>(); var valueProvider = serviceProvider.GetService<IProvideValueTarget>() as IProvideParentValues ?? throw new ArgumentException("serviceProvider does not provide an IProvideValueTarget"); ... } }
Если расширение разметки не использует какую-либо службу от поставщика услуг, класс должен быть замечен.
[AcceptEmptyServiceProvider]
Эти заметки необходимы из-за оптимизации компилятора XAML, которая позволяет создавать более эффективный код, что помогает уменьшить размер приложения и повысить производительность среды выполнения.