第十三章:位图(五)

简介:

浏览和等待
ImageBrowser程序演示了Image的另一个功能,它允许您浏览本书中某些示例所使用的库存照片。 正如您在下面的XAML文件中看到的那样,Image元素与Label和两个Button视图共享屏幕。 请注意,在Image上设置了PropertyChanged处理程序。 您在第11章“可绑定基础结构”中了解到,PropertyChanged处理程序由BindableObject实现,并在绑定属性更改值时触发。

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ImageBrowser.ImageBrowserPage">
 
    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness"
                    iOS="0, 20, 0, 0" />
    </ContentPage.Padding>
 
    <StackLayout>
        <Image x:Name="image"
               VerticalOptions="CenterAndExpand"
               PropertyChanged="OnImagePropertyChanged" />
        <Label x:Name="filenameLabel"
               HorizontalOptions="Center" />
 
        <ActivityIndicator x:Name="activityIndicator" />
        <StackLayout Orientation="Horizontal">
            <Button x:Name="prevButton"
                    Text="Previous"
                    IsEnabled="false"
                    HorizontalOptions="CenterAndExpand"
                    Clicked="OnPreviousButtonClicked" />
            <Button x:Name="nextButton"
                    Text="Next"
                    IsEnabled="false"
                    HorizontalOptions="CenterAndExpand"
                    Clicked="OnNextButtonClicked" />
        </StackLayout>
    </StackLayout>
</ContentPage>

此页面上还有一个ActivityIndicator。 当程序等待长操作完成(例如下载位图)但通常无法提供有关操作进度的任何信息时,通常会使用此元素。 如果您的程序知道操作的完成部分,则可以使用ProgressBar。 (ProgressBar将在下一章演示。)
ActivityIndi​​cator有一个名为IsRunning的布尔属性。通常,该财产是
false,ActivityIndi​​cator不可见。将该属性设置为true可使ActivityIn?dicator可见。所有这三个平台都实现了一个动画视觉,表明该程序正在运行,但在每个平台上看起来都有点不同。在iOS上它是一个旋转轮,在Android上它是一个旋转的部分圆圈。在Windows设备上,一系列点在屏幕上移动。
为了提供对库存图像的浏览访问,ImageBrowser需要下载包含所有文件名列表的JSON文件。多年来,各种版本的.NET引入了几个能够通过Web下载对象的类。但是,并非所有这些都可用于可移植类库中的.NET版本,该类库具有与Xamarin.Forms兼容的配置文件。可用的类是WebRequest及其后代类HttpWebRequest。
WebRequest.Create方法基于URI返回WebRequest方法。 (返回值实际上是一个HttpWebRequest对象。)BeginGetResponse方法需要一个回调函数,当引用URI的Stream可用于访问时,该函数被调用。通过调用EndGetResponse和GetResponseStream可以访问Stream。
一旦程序在以下代码中访问Stream对象,它就会使用DataCon?tractJsonSerializer类以及在ImageBrowserPage类顶部附近定义的嵌入式ImageList类,将JSON文件转换为ImageList对象:

public partial class ImageBrowserPage : ContentPage
{
    [DataContract]
    class ImageList
    {
        [DataMember(Name = "photos")]
        public List<string> Photos = null;
    }
    WebRequest request;
    ImageList imageList;
    int imageListIndex = 0;
    public ImageBrowserPage()
    {
        InitializeComponent();
        // Get list of stock photos.
        Uri uri = new Uri("https://developer.xamarin.com/demo/stock.json");
        request = WebRequest.Create(uri);
        request.BeginGetResponse(WebRequestCallback, null);
    }
    void WebRequestCallback(IAsyncResult result)
    {
        Device.BeginInvokeOnMainThread(() =>
        {
            try
            {
                Stream stream = request.EndGetResponse(result).GetResponseStream();
                // Deserialize the JSON into imageList;
                var jsonSerializer = new DataContractJsonSerializer(typeof(ImageList));
                imageList = (ImageList)jsonSerializer.ReadObject(stream);
                if (imageList.Photos.Count > 0)
                    FetchPhoto();
            }
            catch (Exception exc)
            {
                filenameLabel.Text = exc.Message;
            }
        });
    }
    void OnPreviousButtonClicked(object sender, EventArgs args)
    {
        imageListIndex--;
        FetchPhoto();
    }
    void OnNextButtonClicked(object sender, EventArgs args)
    {
        imageListIndex++;
        FetchPhoto();
    }
    void FetchPhoto()
    {
        // Prepare for new image.
        image.Source = null;
        string url = imageList.Photos[imageListIndex];
        // Set the filename.
        filenameLabel.Text = url.Substring(url.LastIndexOf('/') + 1);
        // Create the UriImageSource.
        UriImageSource imageSource = new UriImageSource
        {
            Uri = new Uri(url + "?Width=1080"),
            CacheValidity = TimeSpan.FromDays(30)
        };
        // Set the Image source.
        image.Source = imageSource;
        // Enable or disable buttons.
        prevButton.IsEnabled = imageListIndex > 0;
        nextButton.IsEnabled = imageListIndex < imageList.Photos.Count - 1;
    }
    void OnImagePropertyChanged(object sender, PropertyChangedEventArgs args)
    {
        if (args.PropertyName == "IsLoading")
        {
            activityIndicator.IsRunning = ((Image)sender).IsLoading;
        }
    }
}

WebRequestCallback方法的整个主体都包含在lambda函数中,该函数是Device.BeginInvokeOnMainThread方法的参数。 WebRequest下载由辅助执行线程中的URI引用的文件。这可以确保操作不会阻止正在处理用户界面的程序的主线程。回调方法也在此辅助线程中执行。但是,可以访问Xamarin.Forms应用程序中的用户界面对象
仅来自主线程。
Device.BeginInvokeOnMainThread方法的目的是解决此问题。此方法的参数排队等待在程序的主线程中运行,并可以安全地访问用户界面对象。
当您单击这两个按钮时,对FetchPhoto的调用使用UriImageSource来下载新位图。这可能需要一秒钟左右。 Image类定义一个名为IsLoading的Boolean属性,当Image处于加载(或下载)位图的过程中时,该属性为true。 IsLoading由可绑定属性IsLoadingProperty支持。这也意味着每当IsLoading更改值时,都会触发PropertyChanged事件。该程序使用PropertyChanged事件处理程序 - 类的最底部的OnImagePropertyChanged方法 - 将ActivityIndi​​cator的IsRunning prop.erty设置为与Image的IsLoading属性相同的值。
您将在第16章“数据绑定”中看到,您的应用程序如何链接IsLoading和IsRunning等属性,以便它们在没有任何显式事件处理程序的情况下保持相同的值。
这是ImageBrowser的实际应用:
201808172234020390
某些图像设置了EXIF方向标志,如果特定平台忽略该标志,则图像会侧向显示。
如果以横向模式运行此程序,您将发现按钮消失。 这个程序的更好的布局选项是Grid,第17章对此进行了演示。

目录
相关文章
|
Java
如何用Java实现位图转矢量图?
通过前面几篇图片转字符、灰度图的文章介绍之后,接下来我们再来看一个有意思的东西,基于前文的基础,实现位图转矢量图的功能
1381 0
如何用Java实现位图转矢量图?
|
7月前
|
存储 算法 C++
【C++入门到精通】位图 | 位图的实现[ C++入门 ]
【C++入门到精通】位图 | 位图的实现[ C++入门 ]
77 0
|
7月前
|
XML 算法 Java
Android App开发之位图加工Bitmap中转换位图的像素色彩、裁剪内部区域、利用矩阵变换位图的讲解及实战(附源码和演示)
Android App开发之位图加工Bitmap中转换位图的像素色彩、裁剪内部区域、利用矩阵变换位图的讲解及实战(附源码和演示)
117 0
|
算法 NoSQL C#
C#位图BitArray 小试牛刀
难缠的布隆过滤器,这次终于通透了
C#位图BitArray 小试牛刀
Halcon把8位图转换为24位图的方法
Halcon把8位图转换为24位图的方法
479 0
|
Android开发 Windows iOS开发
|
JavaScript Android开发 iOS开发
|
存储 编解码 Android开发
|
JavaScript Android开发 索引
|
存储 JavaScript Android开发