Xamarin-异步数据绑定 [英] Xamarin - Asynchronous data binding

查看:114
本文介绍了Xamarin-异步数据绑定的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码:

包含大量图像的页面,这些图像随数据绑定动态加载:

Page with lots of images, that are loaded dynamically with the databinding:

 base.OnAppearing();
        if (!loaded)
        {
            loaded = true;

            BindingContext = new GalleryViewModel(pCode, gCode, gUrl);

        }

viewmodel:

viewmodel:

namespace GalShare.ViewModel
{
class GalleryViewModel
{
    public string pCode { get; set; }
    public string gCode { get; set; }
    public string gUrl { get; set; }
    public ObservableCollection<picdata> Galleries { get; set; }          
    public  GalleryViewModel(string pCode, string gCode, string gUrl)
    {
        this.pCode = pCode;
        this.gCode = gCode;
        this.gUrl = gUrl;
        Galleries = new GalleryService().GetImageList(pCode,gCode,gUrl);

    }

}
}

galleryservice.cs

galleryservice.cs

   class GalleryService
 {

    public ObservableCollection<picdata> Images { get; set; }
    public ObservableCollection<picdata> GetImageList(string pCode, string gCode, string gUrl)
    {
        WebClient client = new WebClient();
        Images = new ObservableCollection<picdata>();
        string downloadString = client.DownloadString(gUrl);
        var deserialized = JsonConvert.DeserializeObject<JsonTxt>(downloadString);

            foreach (File img in deserialized.Files)
            {
               Images.Add(new picdata()
               {
                    ImageName = img.file,
                    BaseUrl = deserialized.Settings.Path.ToString(),
                    ThumbUrl = deserialized.Settings.Path.ToString() + "/thumbs" + img.file
               });
            }
        return Images;
    }
}

页面的XAML:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         xmlns:vm="clr-namespace:GalShare.ViewModel"
         xmlns:d="http://xamarin.com/schemas/2014/forms/design"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         xmlns:ffimageloading="clr-namespace:FFImageLoading.Forms;assembly=FFImageLoading.Forms"
         mc:Ignorable="d"
         x:Class="GalShare.Views.Gallery">

<StackLayout>
    <CollectionView ItemsSource="{Binding Galleries}" x:Name="myCollection" SelectionMode="Single" SelectionChanged="CollectionView_SelectionChanged">
        <CollectionView.ItemsLayout>
            <GridItemsLayout Orientation="Vertical"
                    Span="2" />
        </CollectionView.ItemsLayout>
        <CollectionView.ItemTemplate>
            <DataTemplate>
                <ffimageloading:CachedImage Source="{Binding ThumbUrl}" CacheDuration="1" HorizontalOptions="Fill" VerticalOptions="Fill" DownsampleToViewSize="False"></ffimageloading:CachedImage>
            </DataTemplate>
        </CollectionView.ItemTemplate>
    </CollectionView>
</StackLayout>

</ContentPage>

该代码有效,但是鉴于图像是从Web加载的,而在我加载数据时,该应用程序已锁定.如何异步完成此操作?我想加载目标页面,然后在我在那里的时候加载内容..目前,该应用程序冻结在加载该页面的页面上,直到全部加载完毕.

The code works, but given that the images are loaded from the web, while I am loading the data the App is locked. How can this be done asynchronously? I'd like to load the destination page, and then load the content while I'm there.. Currently the app freezes on the page that loads this one until all is loaded.

我尝试执行任务/等待但没有成功.我认为我必须四处走动才能异步运行代码,但无法弄清楚该怎么做.

I have tried with tasks/await but with no success. I think i have to move some things around to run the code asynchronously but cannot figure out how.

推荐答案

您已标记async-await,并在标题中写了异步文字.但是,所有代码都在主线程上运行,而不是异步运行.

You've tagged async-await and writting asynchronous in your title. However, all of your code is running on the main thread and not asynchronously.

与其将数据加载到ViewModel的构造函数中,还不如将其加载到ViewModel的构造函数中.我强烈建议您在Page上使用诸如OnAppearing的生命周期事件,并触发ICommand以异步加载数据.

Instead of loading your data in the constructor of the ViewModel. I highly suggest you use a lifecycle event such as OnAppearing on your Page and fire a ICommand to load your data asynchronously.

此外,我将切换为使用HttpClient及其出色的异步API.像这样:

Additionally I would switch to using HttpClient and its nice async APIs. So something like:

public class GalleryService
{
    private HttpClient _httpClient;

    public GalleryService()
    {
        _httpClient = new HttpClient();
    }

    public async Task<IEnumerable<picdata>> GetImageList(string pCode, string gCode, string gUrl)
    {
        var response = await _httpClient.GetAsync(gUrl).ConfigureAwait(false);
        if (response.IsSuccessStatusCode)
        {
            var json = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
            var deserialized = JsonConvert.DeserializeObject<JsonTxt>(json);

            var images = new List<picdata>();
            foreach(var img in deserialized.Files)
            {
                images.Add(new picdata()
                {
                    ImageName = img.file,
                    BaseUrl = deserialized.Settings.Path.ToString(),
                    ThumbUrl = deserialized.Settings.Path.ToString() + "/thumbs" + img.file
                });
            }

            return images;
        }

        return new picdata[0]; // return empty set
    }
}

和ViewModel:

and ViewModel:

public class GalleryViewModel
{
    private GalleryService _galleryService;

    public ObservableCollection<picdata> Galleries { get; } = new ObservableCollection<picdata>();
    public ICommand GetImagesCommand { get; }

    public GalleryViewModel(string pCode, string gCode, string gUrl)
    {
        _galleryService = new GalleryService();

        GetImagesCommand = new Command(async () => DoGetImagesCommand(pCode, gCode, gUrl));
    }

    private async Task DoGetImagesCommand(string pCode, string gCode, string gUrl)
    {
        var images = await _galleryService.GetImageList(pCode, gCode, gUrl);
        foreach(var image in images)
            Galleries.Add(image);
    }
}

然后在页面的OnAppearing()覆盖中,您可以调用类似以下内容的内容:(BindingContext as GalleryViewModel).GetImagesCommand.Execute(null);

Then in your OnAppearing() override on your page you can call something like: (BindingContext as GalleryViewModel).GetImagesCommand.Execute(null);

在尝试调用命令之前,请确保已设置BindingContext.可以在Page构造函数中使用以下方法完成:

Make sure you set your BindingContext before trying to call the command. This can be done in the Page constructor with:

BindingContext = new GalleryViewModel();

这样,您就不会阻止整个UI,直到完成下载图像为止.或者,您可以在ViewModel的构造函数中使用Task.Run触发一个Task.但是,然后您必须将ObservableCollection的数量编组到UI线程.

This way you are not blocking your entire UI until it is done downloading the images. Alternatively you could fire off a Task with Task.Run in the constructor of the ViewModel. However, then you will have to marshal the population of the ObservableCollection to the UI thread.

这篇关于Xamarin-异步数据绑定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆