Поделиться через


Создание расширений разметки 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, поэтому он является полупрозрачным и отображается серым на белом фоне страницы:

Демонстрация цвета HSL.

Поставщики услуг

С помощью аргумента 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, которая позволяет создавать более эффективный код, что помогает уменьшить размер приложения и повысить производительность среды выполнения.