流式位图
如果ImageSource类没有FromUri或FromResource方法,您仍然可以通过Web访问位图或作为PCL中的资源存储。 您可以使用ImageSource.FromStream或StreamImageSource类执行这两个作业以及其他几个作业。
ImageSource.FromStream方法比StreamImageSource更容易使用,但两者都有点奇怪。 ImageSource.FromStream的参数不是Stream对象,而是返回Stream对象的Func对象(不带参数的方法)。 Stream?ImageSource的Stream属性同样不是Stream对象,而是具有CancellationToken参数并返回Task 对象的Func对象。
访问流
BitmapStreams程序包含一个XAML文件,其中有两个Image元素等待位图,每个Image元素都使用ImageSource.FromStream在代码隐藏文件中设置:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="BitmapStreams.BitmapStreamsPage">
<StackLayout>
<Image x:Name="image1"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Image x:Name="image2"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>
第一个Image是从PCL中的嵌入资源设置的; 第二个是通过Web访问的位图设置的。
在第4章“滚动堆栈”中的BlackCat程序中,您了解了如何在PCL中为使用EmbeddedResource的Build Action存储的任何资源获取Stream对象。 您可以使用相同的技术来访问存储为嵌入资源的位图:
public partial class BitmapStreamsPage : ContentPage
{
public BitmapStreamsPage()
{
InitializeComponent();
// Load embedded resource bitmap.
string resourceID = "BitmapStreams.Images.IMG_0722_512.jpg";
image1.Source = ImageSource.FromStream(() =>
{
Assembly assembly = GetType().GetTypeInfo().Assembly;
Stream stream = assembly.GetManifestResourceStream(resourceID);
return stream;
});
…
}
}
ImageSource.FromStream的参数定义为返回Stream对象的函数,因此该参数在此处表示为lambda函数。 对GetType方法的调用返回BitmapStreamsPage类的类型,GetTypeInfo提供有关该类型的更多信息,包括包含该类型的Assembly对象。 那就是BitmapStream PCL程序集,它是具有嵌入式资源的程序集。 GetManifestResourceStream返回一个Stream对象,它是ImageSource.FromStream想要的返回值。
如果您需要对这些资源的名称提供一点帮助,GetManifestResourceNames将返回一个字符串对象数组,其中包含PCL中的所有资源ID。 如果您无法弄清楚GetManifestResourceStream无法正常工作的原因,请首先检查以确保您的资源具有EmbeddedResource的Build Action,然后调用GetManifestResourceNames以获取所有资源ID。
要通过Web下载位图,可以使用之前在ImageBrowser程序中演示的相同WebRequest方法。 在这个程序中,BeginGetResponse回调是一个lambda函数:
public partial class BitmapStreamsPage : ContentPage
{
public BitmapStreamsPage()
{
…
// Load web bitmap.
Uri uri = new Uri("https://developer.xamarin.com/demo/IMG_0925.JPG?width=512");
WebRequest request = WebRequest.Create (uri);
request.BeginGetResponse((IAsyncResult arg) =>
{
Stream stream = request.EndGetResponse(arg).GetResponseStream();
if (Device.OS == TargetPlatform.WinPhone ||
Device.OS == TargetPlatform.Windows)
{
MemoryStream memStream = new MemoryStream();
stream.CopyTo(memStream);
memStream.Seek(0, SeekOrigin.Begin);
stream = memStream;
}
ImageSource imageSource = ImageSource.FromStream(() => stream);
Device.BeginInvokeOnMainThread(() => image2.Source = imageSource);
}, null);
}
}
BeginGetResponse回调还包含两个嵌入的lambda函数! 回调的第一行获取位图的Stream对象。 此Stream对象不太适合Windows运行时,因此内容将复制到MemoryStream。
下一个语句使用short lambda函数作为ImageSource.FromStream的参数来定义返回该流的函数。 BeginGetResponse回调的最后一行是对Device.BeginInvokeOnMainThread的调用,以将ImageSource对象设置为Image的Source属性。
看起来好像你可以通过使用更多地控制图像的下载WebRequest和ImageSource.FromStream比用ImageSource.FromUri,但是ImageSource.FromUri方法有一个很大的优势:它将下载的位图缓存在应用程序专用的存储区域中。 正如您所见,您可以关闭缓存,但如果您使用Image?Source.FromStream而不是ImageSource.FromUri,您可能会发现需要缓存图像,这将是一个更大的工作。