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 vonIMarkupExtension<Type>
abgeleitetArrayExtension
wird vonIMarkupExtension<Array>
abgeleitetDynamicResourceExtension
wird vonIMarkupExtension<DynamicResource>
abgeleitetBindingExtension
wird vonIMarkupExtension<BindingBase>
abgeleitetConstraintExpression
wird vonIMarkupExtension<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 null
zurü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 IMarkupExtension
ist, 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:
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:
Dienstanbieter
Mithilfe des IServiceProvider
Arguments können ProvideValue
XAML-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.