Freigeben über


Erstellen von XAML-Markuperweiterungen

Auf der programmgesteuerten Ebene ist eine XAML-Markuperweiterung eine Klasse, die die IMarkupExtension Schnittstelle implementiert IMarkupExtension<T> . Sie können den Quellcode der unten beschriebenen Standardmarkuperweiterungen im MarkupExtensions-Verzeichnis des Xamarin.Forms GitHub-Repositorys erkunden.

Es ist auch möglich, eigene XAML-Markup-Erweiterungen zu definieren, indem man von IMarkupExtension oder IMarkupExtension<T> ableitet. Verwenden Sie die generische Form, wenn die Markup-Erweiterung einen Wert eines bestimmten Typs erhält. Dies ist bei mehreren Markuperweiterungen der Xamarin.Forms Fall:

  • TypeExtension wird von IMarkupExtension<Type> abgeleitet
  • ArrayExtension wird von IMarkupExtension<Array> abgeleitet
  • DynamicResourceExtension wird von IMarkupExtension<DynamicResource> abgeleitet
  • BindingExtension wird von IMarkupExtension<BindingBase> abgeleitet
  • ConstraintExpression wird von IMarkupExtension<Constraint> abgeleitet

Die beiden IMarkupExtension-Schnittstellen definieren jeweils nur eine Methode, die ProvideValue genannt wird:

public interface IMarkupExtension
{
    object ProvideValue(IServiceProvider serviceProvider);
}

public interface IMarkupExtension<out T> : IMarkupExtension
{
    new T ProvideValue(IServiceProvider serviceProvider);
}

Da IMarkupExtension<T> von IMarkupExtension abgeleitet ist und das Schlüsselwort new auf ProvideValue enthält, enthält sie beide ProvideValue Methoden.

Sehr häufig definieren XAML-Markuperweiterungen Eigenschaften, die zum Rückgabewert beitragen. (Die offensichtliche Ausnahme ist NullExtension, in der ProvideValue einfach nullzurückgegeben wird.) Die ProvideValue Methode weist ein einzelnes Argument vom Typ IServiceProvider auf, das weiter unten in diesem Artikel erläutert wird.

Eine Markuperweiterung zum Angeben der Farbe

Mit der folgenden XAML-Markuperweiterung können Sie einen Color Wert mithilfe von Farbton-, Sättigungs- und Leuchtdichtekomponenten erstellen. Sie definiert vier Eigenschaften für die vier Komponenten der Farbe, einschließlich einer Alphakomponente, die auf 1 initialisiert wird. Die Klasse leitet sich von IMarkupExtension<Color> ab, um einen Color Rückgabewert anzugeben:

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);
    }
}

Da IMarkupExtension<T> die Klasse abgeleitet IMarkupExtensionist, muss die Klasse zwei ProvideValue Methoden enthalten, eine, die zurückgegeben wird und eine andere, die zurückgegeben Color wird object, aber die zweite Methode kann einfach die erste Methode aufrufen.

Die HSL Color Demo-Seite zeigt eine Vielzahl von Möglichkeiten, die in einer XAML-Datei angezeigt werden können, HslColorExtension um die Farbe für eine 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>

Beachten Sie, dass HslColorExtension bei einem XML-Tag die vier Eigenschaften als Attribute festgelegt werden, aber wenn sie zwischen geschweiften geschweiften Klammern angezeigt wird, werden die vier Eigenschaften durch Kommas ohne Anführungszeichen getrennt. Die Standardwerte für H, S und L sind 0, und der Standardwert von A ist 1, sodass diese Eigenschaften weggelassen werden können, wenn sie auf Standardwerte gesetzt werden sollen. Das letzte Beispiel zeigt ein Beispiel, bei dem die Helligkeit 0 ist, was normalerweise Schwarz ergibt, aber der Alphakanal 0,5 ist, sodass es halb transparent ist und vor dem weißen Hintergrund der Seite grau erscheint:

HSL Color Demo

Eine Markuperweiterung für den Zugriff auf Bitmaps

Das Argument ist ProvideValue ein Objekt, das die IServiceProvider Schnittstelle implementiert, die im .NET-Namespace System definiert ist. Diese Schnittstelle verfügt über ein Element, eine Methode mit einem GetService Type Argument.

Die ImageResourceExtension unten gezeigte Klasse zeigt eine mögliche Verwendung von IServiceProvider und GetService zum Abrufen eines IXmlLineInfoProvider Objekts, das Zeilen- und Zeicheninformationen bereitstellen kann, die angeben, wo ein bestimmter Fehler erkannt wurde. In diesem Fall wird eine Ausnahme ausgelöst, wenn die Source Eigenschaft nicht festgelegt wurde:

[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 ist hilfreich, wenn eine XAML-Datei auf eine Bilddatei zugreifen muss, die als eingebettete Ressource im .NET Standard-Bibliotheksprojekt gespeichert ist. Sie verwendet die Source Eigenschaft, um die statische ImageSource.FromResource Methode aufzurufen. Für diese Methode ist ein vollqualifizierter Ressourcenname erforderlich, der aus dem Assemblynamen, dem Ordnernamen und dem Dateinamen besteht, die durch Punkte getrennt sind. Das zweite Argument für die ImageSource.FromResource Methode stellt den Assemblynamen bereit und ist nur für Releasebuilds auf UWP erforderlich. Unabhängig davon muss von der Assembly, die die Bitmap enthält, aufgerufen werden. Dies bedeutet, dass diese XAML-Ressourcenerweiterung nicht Teil einer externen Bibliothek sein kann, ImageSource.FromResource es sei denn, die Bilder befinden sich ebenfalls in dieser Bibliothek. (Siehe Artikel "Eingebettete Bilder " enthält weitere Informationen zum Zugreifen auf Bitmaps, die als eingebettete Ressourcen gespeichert sind.)

Obwohl ImageResourceExtension die Source Eigenschaft festgelegt werden muss, wird die Source Eigenschaft in einem Attribut als Inhaltseigenschaft der Klasse angegeben. Dies bedeutet, dass der Source= Teil des Ausdrucks in geschweiften Klammern weggelassen werden kann. Auf der Seite "Image Resource Demo " rufen die Image Elemente zwei Bilder mithilfe des Ordnernamens und des Dateinamens durch Punkte getrennt ab:

<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>

Dies ist das Programm, das ausgeführt wird:

Image Resource Demo

Dienstanbieter

Mithilfe des IServiceProvider Arguments können ProvideValueXAML-Markuperweiterungen Zugriff auf hilfreiche Informationen zur XAML-Datei erhalten, in der sie verwendet werden. Um das IServiceProvider Argument jedoch erfolgreich zu verwenden, müssen Sie wissen, welche Art von Diensten in bestimmten Kontexten verfügbar sind. Die beste Möglichkeit, dieses Feature zu verstehen, besteht darin, den Quellcode vorhandener XAML-Markuperweiterungen im Ordner MarkupExtensions im Xamarin.Forms Repository auf GitHub zu untersuchen. Beachten Sie, dass einige Arten von Diensten intern für Xamarin.Forms.

In einigen XAML-Markuperweiterungen kann dieser Dienst nützlich sein:

 IProvideValueTarget provideValueTarget = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;

Die IProvideValueTarget-Schnittstelle definiert zwei Eigenschaften, TargetObject und TargetProperty. Wenn diese Informationen in der ImageResourceExtension Klasse abgerufen werden, TargetObject ist das Image und TargetProperty ist ein BindableProperty Objekt für die Source Eigenschaft von Image. Dies ist die Eigenschaft, für die die XAML-Markup-Erweiterung festgelegt wurde.

Der GetService Aufruf mit einem Argument gibt typeof(IProvideValueTarget) tatsächlich ein Objekt vom Typ zurück SimpleValueTargetProvider, das im Xamarin.Forms.Xaml.Internals Namespace definiert ist. Wenn Sie den Rückgabewert dieses GetService Typs umwandeln, können Sie auch auf eine ParentObjects Eigenschaft zugreifen, bei der es sich um ein Array handelt, das das Image Element, das Grid übergeordnete Element und das ImageResourceDemoPage übergeordnete Element enthält Grid.

Zusammenfassung

XAML-Markuperweiterungen spielen eine wichtige Rolle in XAML, indem sie die Möglichkeit zum Festlegen von Attributen aus einer Vielzahl von Quellen erweitern. Wenn die vorhandenen XAML-Markuperweiterungen darüber hinaus nicht genau das bereitstellen, was Sie benötigen, können Sie auch eigene Schreiben.