Membuat Ekstensi Markup XAML
Pada tingkat terprogram, ekstensi markup XAML adalah kelas yang mengimplementasikan IMarkupExtension
antarmuka atau IMarkupExtension<T>
. Anda dapat menjelajahi kode sumber ekstensi markup standar yang dijelaskan di bawah ini di direktori MarkupExtensions repositori Xamarin.Forms GitHub.
Anda juga dapat menentukan ekstensi markup XAML kustom Anda sendiri dengan berasal dari IMarkupExtension
atau IMarkupExtension<T>
. Gunakan formulir generik jika ekstensi markup mendapatkan nilai dari jenis tertentu. Ini adalah kasus dengan beberapa Xamarin.Forms ekstensi markup:
TypeExtension
berasal dariIMarkupExtension<Type>
ArrayExtension
berasal dariIMarkupExtension<Array>
DynamicResourceExtension
berasal dariIMarkupExtension<DynamicResource>
BindingExtension
berasal dariIMarkupExtension<BindingBase>
ConstraintExpression
berasal dariIMarkupExtension<Constraint>
Kedua IMarkupExtension
antarmuka hanya menentukan satu metode masing-masing, bernama ProvideValue
:
public interface IMarkupExtension
{
object ProvideValue(IServiceProvider serviceProvider);
}
public interface IMarkupExtension<out T> : IMarkupExtension
{
new T ProvideValue(IServiceProvider serviceProvider);
}
Karena IMarkupExtension<T>
berasal dari IMarkupExtension
dan menyertakan new
kata kunci pada ProvideValue
, kata kunci berisi kedua ProvideValue
metode.
Sangat sering, ekstensi markup XAML menentukan properti yang berkontribusi pada nilai pengembalian. (Pengecualian yang jelas adalah NullExtension
, di mana ProvideValue
hanya mengembalikan null
.) Metode ProvideValue
ini memiliki argumen tunggal jenis IServiceProvider
yang akan dibahas nanti dalam artikel ini.
Ekstensi Markup untuk Menentukan Warna
Ekstensi markup XAML berikut memungkinkan Anda membuat Color
nilai menggunakan komponen hue, saturasi, dan luminositas. Ini mendefinisikan empat properti untuk empat komponen warna, termasuk komponen alfa yang diinisialisasi menjadi 1. Kelas berasal dari IMarkupExtension<Color>
untuk menunjukkan nilai pengembalian 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);
}
}
Karena IMarkupExtension<T>
berasal dari IMarkupExtension
, kelas harus berisi dua ProvideValue
metode, satu yang mengembalikan Color
dan yang lain yang mengembalikan object
, tetapi metode kedua cukup memanggil metode pertama.
Halaman Demo Warna HSL menunjukkan berbagai cara yang HslColorExtension
dapat muncul dalam file XAML untuk menentukan warna untuk 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>
Perhatikan bahwa ketika HslColorExtension
adalah tag XML, empat properti diatur sebagai atribut, tetapi ketika muncul di antara kurung kurawal, keempat properti dipisahkan oleh koma tanpa tanda kutip. Nilai default untuk H
, , dan L
adalah 0, dan nilai A
default adalah 1, sehingga properti tersebut dapat dihilangkan jika Anda ingin nilai default diatur S
ke nilai default. Contoh terakhir menunjukkan contoh di mana luminositas adalah 0, yang biasanya menghasilkan hitam, tetapi saluran alfa adalah 0,5, sehingga setengah transparan dan tampak abu-abu terhadap latar belakang putih halaman:
Ekstensi Markup untuk Mengakses Bitmap
Argumen ke ProvideValue
adalah objek yang mengimplementasikan IServiceProvider
antarmuka, yang didefinisikan dalam namespace .NET System
. Antarmuka ini memiliki satu anggota, metode bernama GetService
dengan Type
argumen.
Kelas ImageResourceExtension
yang ditunjukkan di bawah ini menunjukkan satu kemungkinan penggunaan IServiceProvider
dan GetService
untuk mendapatkan IXmlLineInfoProvider
objek yang dapat memberikan informasi baris dan karakter yang menunjukkan di mana kesalahan tertentu terdeteksi. Dalam hal ini, pengecualian dinaikkan ketika Source
properti belum ditetapkan:
[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
sangat membantu ketika file XAML perlu mengakses file gambar yang disimpan sebagai sumber daya yang disematkan dalam proyek pustaka .NET Standard. Ini menggunakan Source
properti untuk memanggil metode statis ImageSource.FromResource
. Metode ini memerlukan nama sumber daya yang sepenuhnya memenuhi syarat, yang terdiri dari nama rakitan, nama folder, dan nama file yang dipisahkan oleh titik. Argumen kedua untuk ImageSource.FromResource
metode ini menyediakan nama rakitan, dan hanya diperlukan untuk rilis build pada UWP. Terlepas dari itu, ImageSource.FromResource
harus dipanggil dari rakitan yang berisi bitmap, yang berarti bahwa ekstensi sumber daya XAML ini tidak dapat menjadi bagian dari pustaka eksternal kecuali gambar juga ada di pustaka tersebut. (Lihat Artikel Gambar Tersemat untuk informasi selengkapnya tentang mengakses bitmap yang disimpan sebagai sumber daya yang disematkan.)
Meskipun ImageResourceExtension
mengharuskan Source
properti diatur, Source
properti ditunjukkan dalam atribut sebagai properti konten kelas. Ini berarti bahwa Source=
bagian ekspresi dalam kurung kurawal dapat dihilangkan. Di halaman Demo Sumber Daya Gambar, Image
elemen mengambil dua gambar menggunakan nama folder dan nama file yang dipisahkan oleh titik:
<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>
Berikut adalah program yang berjalan:
Penyedia Layanan
Dengan menggunakan IServiceProvider
argumen ke ProvideValue
ekstensi markup XAML bisa mendapatkan akses ke informasi bermanfaat tentang file XAML tempat mereka digunakan. Tetapi untuk menggunakan IServiceProvider
argumen dengan sukses, Anda perlu mengetahui jenis layanan apa yang tersedia dalam konteks tertentu. Cara terbaik untuk mendapatkan pemahaman tentang fitur ini adalah dengan mempelajari kode sumber ekstensi markup XAML yang ada di folder MarkupExtensions di Xamarin.Forms repositori di GitHub. Ketahuilah bahwa beberapa jenis layanan bersifat internal untuk Xamarin.Forms.
Dalam beberapa ekstensi markup XAML, layanan ini mungkin berguna:
IProvideValueTarget provideValueTarget = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
Antarmuka IProvideValueTarget
mendefinisikan dua properti, TargetObject
dan TargetProperty
. Ketika informasi ini diperoleh di ImageResourceExtension
kelas , TargetObject
adalah Image
dan TargetProperty
merupakan BindableProperty
objek untuk Source
properti .Image
Ini adalah properti tempat ekstensi markup XAML telah diatur.
Panggilan GetService
dengan argumen typeof(IProvideValueTarget)
benar-benar mengembalikan objek jenis SimpleValueTargetProvider
, yang didefinisikan dalam Xamarin.Forms.Xaml.Internals
namespace. Jika Anda melemparkan nilai GetService
pengembalian ke jenis tersebutGrid
, Anda juga dapat mengakses ParentObjects
properti, yang merupakan array yang berisi Image
elemen, Grid
induk, dan ImageResourceDemoPage
induk dari .
Kesimpulan
Ekstensi markup XAML memainkan peran penting dalam XAML dengan memperluas kemampuan untuk mengatur atribut dari berbagai sumber. Selain itu, jika ekstensi markup XAML yang ada tidak menyediakan apa yang Anda butuhkan, Anda juga dapat menulis sendiri.