Reputation: 4173
I have a page built like this:
<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>
<Image Source="{Binding ThumbUrl}"
Aspect="AspectFit" />
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<ActivityIndicator BindingContext="{x:Reference myCollection}" IsRunning="{Binding IsLoading}"/>
</StackLayout>
The binding source returns a lot of URLs to images that are then displayed like a gallery. Since it takes a few seconds to load the page, I would like to show the activity indicator. I do have another page, that links to the various galleries. This is how The page loads up the gallery page:
private void CollectionView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.CurrentSelection.Count > 0)
{
var item = (GalleryListEntry)e.CurrentSelection.FirstOrDefault();
((CollectionView)sender).SelectedItem = null;
Navigation.PushModalAsync(new Gallery(item.PCode, item.GCode));
}
}
problem is that whenever I click on this page, it freezes, till the gallery is loaded and then jumps directly to the gallery. I would like it to display the gallery (empty) with the activity indicator, till the gallery is loaded, instead of freezing..
What am I doing wrong?
EDIT: as requested, code for Gallery page:
Gallery.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"
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>
<Image Source="{Binding ThumbUrl}"
Aspect="AspectFit" />
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<ActivityIndicator BindingContext="{x:Reference myCollection}" IsRunning="{Binding IsLoading}"/>
</StackLayout>
gallery.xaml.cs
using GalShare.Model;
using GalShare.ViewModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace GalShare.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class Gallery : ContentPage
{
public Gallery(string photographerCode, string galleryCode)
{
InitializeComponent();
BindingContext = new GalleryViewModel(photographerCode, galleryCode);
}
}
}
GalleryViewModel.cs
using GalShare.Model;
using GalShare.Service;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
namespace GalShare.ViewModel
{
class GalleryViewModel
{
public string pCode { get; set; }
public string gCode { get; set; }
public ObservableCollection<picdata> Galleries { get; set; }
public GalleryViewModel(string pCode, string gCode)
{
this.pCode = pCode;
this.gCode = gCode;
Galleries = new GalleryService().GetImageList(pCode,gCode);
}
}
}
GalleryService.cs
using GalShare.Model;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Net;
using System.Text;
namespace GalShare.Service
{
public class JsonGalListTxt
{
public string Galurl { get; set; }
}
public class JsonTxt
{
public Settings Settings { get; set; }
public IList<File> Files { get; set; }
}
public class Settings
{
public string Path { get; set; }
}
public class File
{
public string file { get; set; }
}
public class galURL
{
public string galurl { get; set; }
}
class GalleryService
{
// public string pCode { get; set; }
// public string gCode { get; set; }
public ObservableCollection<picdata> Images { get; set; }
public ObservableCollection<picdata> GetImageList(string pCode, string gCode)
{
WebClient client = new WebClient();
string GalUrl = client.DownloadString("https://www.mypage.it/getUrl.php?pid=" + pCode + "&galid=" + gCode);
var deserializedUrl = JsonConvert.DeserializeObject<galURL>(GalUrl);
Images = new ObservableCollection<picdata>();
string downloadString = client.DownloadString(deserializedUrl.galurl);
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;
}
}
}
Upvotes: 1
Views: 935
Reputation: 89117
when you create your VM from the constructor, it is loading ALL of the images on the main thread, blocking the page from actually appearing until it completes
public Gallery(string photographerCode, string galleryCode)
{
InitializeComponent();
BindingContext = new GalleryViewModel(photographerCode, galleryCode);
}
at a minimum, I would move this to OnAppearing
, so that the page will display first, and then load the images.
You may also want to move the image requests to another thread so it doesn't block the UI. You could also use a library like FFImageLoading which helps manage this for you
Upvotes: 1