Xamarin.FormsでEmbedded Resourceの画像を使う
Xamarin.formsで組み込みの画像を使う方法
Xamarin.Formsで使う画像は画像リソースはプラットフォームのプロジェクトごとに持たせるようになっている.
しかし,同じ画像を各プロジェクトにコピーしなければならないし,その管理をする必要があるので面倒.
これを共通コード側に持たせることで,上記の手間をなくすことができる.
こちらのブログのおまけのところも参考に. rksoftware.hatenablog.com
画像をEmbedded Resourceとしてプロジェクトに追加する
追加自体は特に難しくない. プロジェクトにドラッグアンドドロップするだけ.
次に画像ファイルのプロパティを開いて,
Build Action
をEmbedded Resource
にする.
マークアップ拡張を作成する
リソースを表す文字列からImageSourceを返すマークアップ拡張を作成する.
[ContentProperty(nameof(Source))]
属性をつけることを忘れないこと.
namespace XFEmbeddedImages.Extensions { [ContentProperty(nameof(Source))] class ImageResourceExtension : IMarkupExtension { public string Source { get; set; } public object ProvideValue(IServiceProvider serviceProvider) { if (Source == null) { return null; } var imageSource = ImageSource.FromResource(Source, typeof(ImageResourceExtension).GetTypeInfo().Assembly); return imageSource; } } }
XAML側ではこのマークアップ拡張を利用するために,上記のクラスの名前空間を追加します.
xmlns:local="clr-namespace:XFEmbeddedImages.Extensions"
そしてEmbedded Resourceにした画像ファイルを以下の形で指定します.
名前空間.フォルダ名.ファイル名
<?xml version="1.0" encoding="utf-8" ?> <ContentPage x:Class="XFEmbeddedImages.MainPage" xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:d="http://xamarin.com/schemas/2014/forms/design" xmlns:local="clr-namespace:XFEmbeddedImages.Extensions" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <StackLayout> <Image Source="{local:ImageResource XFEmbeddedImages.Images.avatar_men_2.jpg}" /> </StackLayout> </ContentPage>
実行すると,画像が表示される.
バインディングのときはどうするの?
上で書いたとおり,埋め込みリソースの画像を使用するには文字列で埋め込みリソースを指定して,それを使ってImageSourceを作成している.
ということで,ImageのSourceプロパティに文字列をバインディングして,それをConverterでImageSourceに変換すればいいということかと.
以下のようなConverterを定義する. IMarkupExtensionを実装することでXAML側で使いやすくしておく.
public class ImageSourceConverter : IMarkupExtension, IValueConverter { //Source→View //ViewModelやコードビハインドからXaml側へ public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { string embeddedResourcePath = (string)value; var imageSource = ImageSource.FromResource(embeddedResourcePath, typeof(ImageResourceExtension).GetTypeInfo().Assembly); return imageSource; } //View→Source //Xaml側からViewModelやコードビハインドへ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } public object ProvideValue(IServiceProvider serviceProvider) { return this; } }
コードビハインド側は以下のようにバインディング元のプロパティを用意し,埋め込みリソースを指定する文字列(名前空間.フォルダ名.ファイル名
)を設定しておく.
public partial class MainPage : ContentPage { public string ResourcePath { get; set; } = "XFEmbeddedImages.Images.avatar_men_2.jpg"; public MainPage() { InitializeComponent(); this.BindingContext = this; } }
XAML側では以下のように通常のバインディングとコンバーターの使い方をすればよい.
<Image Source="{Binding ResourcePath, Converter={local:ImageSourceConverter}}" />
実行すると以下のように画像が表示され,バインディングで画像を表示できることが確認できる.
メモ
[ContentProperty(nameof(Source))] public sealed class ImageResourceExtension : IMarkupExtension { public string Source { get; set; } public object ProvideValue(IServiceProvider serviceProvider) { if (Source == null) return null; return ImageSource.FromResource(Source); } }